From 90000d36b2c9fae84f3bde8737df3dbdd530d85a Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:57:03 +0300 Subject: [PATCH 01/28] feat(test): Add tests for 'cloud instance get' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_get_test.go | 306 ++++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 test/e2e/cloud/instance_get_test.go diff --git a/test/e2e/cloud/instance_get_test.go b/test/e2e/cloud/instance_get_test.go new file mode 100644 index 000000000..7347fafea --- /dev/null +++ b/test/e2e/cloud/instance_get_test.go @@ -0,0 +1,306 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud vm get", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + var instanceNameFull string + + const ( + imageName = "nginx:latest" + instanceName = "instance-get-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + fmt.Println(instanceNameFull) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + }) + + When("invoked with an instance name", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, instanceNameFull) + }) + + It("should show the instance in list format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + instanceNameFull)) + }) + }) + + When("invoked with an instance name and the list output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "list", instanceNameFull) + }) + + It("should show the instance in list format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + instanceNameFull)) + }) + }) + + When("invoked with an instance name and the json output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "json", instanceNameFull) + }) + + It("should show the instance in json format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + instanceNameFull + `"`)) + }) + }) + + When("invoked with an instance name and the raw output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "raw", instanceNameFull) + }) + + It("should show the instance in raw format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + + // Field exclusive to the raw output format + Expect(stdout.String()).To(MatchRegexp(`"status":"success"`)) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + instanceNameFull + `"`)) + }) + }) + + When("invoked with an instance name and the table output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "table", instanceNameFull) + }) + + It("should show the instance in table format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + + // Output exclusive to the table output format + Expect(stdout.String()).To(MatchRegexp(`NAME`)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + }) + }) + + When("invoked with an instance name and an invalid output format", func() { + format := "invalid" + + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", format, instanceNameFull) + }) + + It("should error out and print a message", func() { + err := cmd.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`invalid output format: ` + format)) + }) + }) + + When("invoked with two instance names and the table output format", func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd.Args = append(cmd.Args, "-o", "table", instanceNameFull, instanceNameFull2) + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull2) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + }) + + It("should show the instances in table format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + + // Output exclusive to the table output format + Expect(stdout.String()).To(MatchRegexp(`NAME`)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull2)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Retrieve the state of an instance`)) + }) + }) +}) From e247d1f202d1ebd55d7fcc7937513db8bd2d43b0 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:57:15 +0300 Subject: [PATCH 02/28] feat(test): Add tests for 'cloud instance list' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_list_test.go | 241 +++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 test/e2e/cloud/instance_list_test.go diff --git a/test/e2e/cloud/instance_list_test.go b/test/e2e/cloud/instance_list_test.go new file mode 100644 index 000000000..0bf03b3d9 --- /dev/null +++ b/test/e2e/cloud/instance_list_test.go @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud vm ls", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + var instanceNameFull string + + const ( + imageName = "nginx:latest" + instanceName = "instance-ls-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "vm", "ls", "--log-level", "info", "--log-type", "json") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + }) + + When("invoked with no flags", func() { + It("should show all instances in table format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`NAME`)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + }) + }) + + When("invoked with the list output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "list") + }) + + It("should show instances in the list format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + instanceNameFull)) + }) + }) + + When("invoked with the json output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "json") + }) + + It("should instances in the json format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + instanceNameFull + `"`)) + }) + }) + + When("invoked with the raw output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "raw") + }) + + It("should show instances in the raw format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + + // Field exclusive to the raw output format + Expect(stdout.String()).To(MatchRegexp(`"status":"success"`)) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + instanceNameFull + `"`)) + }) + }) + + When("invoked with the table output format", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", "table") + }) + + It("should show instances in the table format", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + + // Output exclusive to the table output format + Expect(stdout.String()).To(MatchRegexp(`NAME`)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + }) + }) + + When("invoked with an invalid output format", func() { + format := "invalid" + + BeforeEach(func() { + cmd.Args = append(cmd.Args, "-o", format) + }) + + It("should error out and print a message", func() { + err := cmd.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`invalid output format: ` + format)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`List all instances in your account`)) + }) + }) +}) From 4ca6fd3fa6361b9b1f99a113e3702b9dcf1b344f Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:57:25 +0300 Subject: [PATCH 03/28] feat(test): Add tests for 'cloud instance logs' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_logs_test.go | 328 +++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 test/e2e/cloud/instance_logs_test.go diff --git a/test/e2e/cloud/instance_logs_test.go b/test/e2e/cloud/instance_logs_test.go new file mode 100644 index 000000000..cc8e4c21e --- /dev/null +++ b/test/e2e/cloud/instance_logs_test.go @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud vm logs", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + var instanceNameFull string + + const ( + imageName = "nginx:latest" + instanceName = "instance-logs-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull, + "--start", + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "vm", "logs", "--log-level", "info", "--log-type", "json") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + }) + + When("invoked with an instance name", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, instanceNameFull) + }) + + It("should show all log lines", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Powered by Unikraft`)) + Expect(stdout.String()).To(MatchRegexp(`1: Set IPv4 address`)) + }) + }) + + When("invoked with an instance name and the tail flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--tail", "1", instanceNameFull) + }) + + It("should show only the last given lines from the log", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Powered by Unikraft`)) + Expect(stdout.String()).ToNot(MatchRegexp(`1: Set IPv4 address`)) + }) + }) + When("invoked with an instance name and the follow flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--follow", instanceNameFull) + }) + + It("should show all lines in the log and wait for input", func() { + err := cmd.Start() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + // Check if the process is running + pid := cmd.Process.Pid + _, err = os.FindProcess(pid) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + }) + + When("invoked with two instance names", func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + "--start", + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + + cmd.Args = append(cmd.Args, instanceNameFull, instanceNameFull2) + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull2) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + }) + + It("should show all log lines and a prefix for each instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Powered by Unikraft`)) + Expect(stdout.String()).To(MatchRegexp(`1: Set IPv4 address`)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull2)) + }) + }) + + When("invoked with two instance names and the 'no-prefix' flag", func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + "--start", + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + + cmd.Args = append(cmd.Args, "--no-prefix", instanceNameFull, instanceNameFull2) + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull2) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + }) + + It("should show all log lines and and no prefix", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Powered by Unikraft`)) + Expect(stdout.String()).To(MatchRegexp(`1: Set IPv4 address`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Get console output of an instance`)) + }) + }) +}) From 815123ca8b974f5fbfdf72fb2f0cbd2cf5601a78 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:57:38 +0300 Subject: [PATCH 04/28] feat(test): Add tests for 'cloud instance remove' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_remove_test.go | 346 +++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 test/e2e/cloud/instance_remove_test.go diff --git a/test/e2e/cloud/instance_remove_test.go b/test/e2e/cloud/instance_remove_test.go new file mode 100644 index 000000000..84e83e052 --- /dev/null +++ b/test/e2e/cloud/instance_remove_test.go @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud vm rm", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + var instanceNameFull string + + const ( + imageName = "nginx:latest" + instanceName = "instance-remove-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull, + "--start", + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with the all flag", Serial, func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--all") + }) + + It("should remove all instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 1 instance`)) + + // Check if the instance still exists + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("No instance with name '" + instanceNameFull + "'")) + }) + }) + + When("invoked with the instance name", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, instanceNameFull) + }) + + It("should remove the instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 1 instance`)) + + // Check if the instance still exists + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("No instance with name '" + instanceNameFull + "'")) + }) + }) + + When("invoked with two instance names", func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd.Args = append(cmd.Args, instanceNameFull, instanceNameFull2) + }) + + It("should remove the instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 2 instance`)) + + // Check if the instance still exists + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("No instance with name '" + instanceNameFull + "'")) + + // Check if the instance still exists + getCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd2.Env = os.Environ() + getCmd2.Args = append(getCmd2.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull2) + + err = getCmd2.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("No instance with name '" + instanceNameFull2 + "'")) + }) + }) + + When("invoked with the 'stopped' flag", Serial, func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd.Args = append(cmd.Args, "--stopped") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 1 instance`)) + }) + + It("should remove only the stopped instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 1 instance`)) + + // Check if the instance still exists + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + // Check if the instance still exists + getCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd2.Env = os.Environ() + getCmd2.Args = append(getCmd2.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull2) + + err = getCmd2.Run() + + Expect(err).To(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("No instance with name '" + instanceNameFull2 + "'")) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 1 instance`)) + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Remove a`)) + }) + }) +}) From dd898736bc0eeb2acbc74f602e6295a76ca67192 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:57:50 +0300 Subject: [PATCH 05/28] feat(test): Add tests for 'cloud instance start' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_start_test.go | 316 ++++++++++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 test/e2e/cloud/instance_start_test.go diff --git a/test/e2e/cloud/instance_start_test.go b/test/e2e/cloud/instance_start_test.go new file mode 100644 index 000000000..6ee6e4431 --- /dev/null +++ b/test/e2e/cloud/instance_start_test.go @@ -0,0 +1,316 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud vm start", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + var instanceNameFull string + + const ( + imageName = "nginx:latest" + instanceName = "instance-start-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "vm", "start", "--log-level", "info", "--log-type", "json") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + }) + + When("invoked with the instance name and the wait flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--wait", "1m", instanceNameFull) + }) + + It("should start the instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`starting 1 instance`)) + + // Check if the instance is running + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + }) + }) + + When("invoked with the all flag", Serial, func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--all") + }) + + It("should start all instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`starting 1 instance`)) + + // Check if the instance is running + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + }) + }) + + When("invoked with the instance name", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, instanceNameFull) + }) + + It("should start the instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`starting 1 instance`)) + + // Check if the instance is running + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + }) + }) + + When("invoked with two instance names", func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + cmd.Args = append(cmd.Args, instanceNameFull, instanceNameFull2) + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull2) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + }) + + It("should start the instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`starting 2 instance`)) + + // Check if the instance is running + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + + // Check if the instance is running + getCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd2.Env = os.Environ() + getCmd2.Args = append(getCmd2.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull2) + + err = getCmd2.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Start an instance`)) + }) + }) +}) From 80b88c299729513ab2b279b5769a38ca59544b07 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:57:57 +0300 Subject: [PATCH 06/28] feat(test): Add tests for 'cloud instance stop' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_stop_test.go | 380 +++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 test/e2e/cloud/instance_stop_test.go diff --git a/test/e2e/cloud/instance_stop_test.go b/test/e2e/cloud/instance_stop_test.go new file mode 100644 index 000000000..f4e46e352 --- /dev/null +++ b/test/e2e/cloud/instance_stop_test.go @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud vm stop", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + var instanceNameFull string + + const ( + imageName = "nginx:latest" + instanceName = "instance-stop-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull, + "--start", + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "vm", "stop", "--log-level", "info", "--log-type", "json") + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + }) + + When("invoked with the instance name and the wait flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--wait", "30m", instanceNameFull) + }) + + It("should stop the instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopping 1 instance`)) + + // Check if the instance is stopped + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + }) + }) + + When("invoked with the instance name and the drain flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--drain-timeout", "30m", instanceNameFull) + }) + + It("should stop the instance after draining all connections", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopping 1 instance`)) + + // Check if the instance is stopped + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + }) + }) + + When("invoked with the all flag", Serial, func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--all") + }) + + It("should stop all instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopping 1 instance`)) + + // Check if the instance is stopped + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + }) + }) + + When("invoked with the instance name", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, instanceNameFull) + }) + + It("should stop the instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopping 1 instance`)) + + // Check if the instance is stopped + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + }) + }) + + When("invoked with the instance name and force", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--force", instanceNameFull) + }) + + It("should stop the instance", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopping 1 instance`)) + + // Check if the instance is stopped + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + }) + }) + + When("invoked with two instance names", func() { + var instanceNameFull2 string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "-o", "json") + + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull2 = fmt.Sprintf("%s-%d", instanceName, id) + + createCmd.Args = append(createCmd.Args, + "--memory", instanceMemory, + "--name", instanceNameFull2, + "--start", + imageName, + ) + + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`running`)) + + cmd.Args = append(cmd.Args, instanceNameFull, instanceNameFull2) + }) + + AfterEach(func() { + rmCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd.Env = os.Environ() + rmCmd.Args = append(rmCmd.Args, "cloud", "vm", "rm", "--log-level", "info", "--log-type", "json", instanceNameFull2) + + err := rmCmd.Run() + if err != nil { + fmt.Print(rmCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + }) + + It("should stop the instances", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopping 2 instance`)) + + // Check if the instance is stopped + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + + // Check if the instance is stopped + getCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd2.Env = os.Environ() + getCmd2.Args = append(getCmd2.Args, "cloud", "vm", "get", "--log-level", "info", "--log-type", "json", "-o", "json", instanceNameFull2) + + err = getCmd2.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`stopped`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Stop instances`)) + }) + }) +}) From 16c50bd49bc579802ff8d59c3acd336b32448863 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:58:44 +0300 Subject: [PATCH 07/28] feat(test): Rename test suite to 'cloud' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/cloud_suite_test.go | 2 +- test/e2e/cloud/img_list_test.go | 2 +- test/e2e/cloud/instance_create_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/cloud/cloud_suite_test.go b/test/e2e/cloud/cloud_suite_test.go index 68a794b41..efd9cce17 100644 --- a/test/e2e/cloud/cloud_suite_test.go +++ b/test/e2e/cloud/cloud_suite_test.go @@ -3,7 +3,7 @@ // Licensed under the BSD-3-Clause License (the "License"). // You may not use this file except in compliance with the License. -package cli_test +package cloud_test import ( "testing" diff --git a/test/e2e/cloud/img_list_test.go b/test/e2e/cloud/img_list_test.go index 4a040abae..3a448243a 100644 --- a/test/e2e/cloud/img_list_test.go +++ b/test/e2e/cloud/img_list_test.go @@ -3,7 +3,7 @@ // Licensed under the BSD-3-Clause License (the "License"). // You may not use this file except in compliance with the License. -package cli_test +package cloud_test import ( "fmt" diff --git a/test/e2e/cloud/instance_create_test.go b/test/e2e/cloud/instance_create_test.go index ab757c77e..bc4943171 100644 --- a/test/e2e/cloud/instance_create_test.go +++ b/test/e2e/cloud/instance_create_test.go @@ -3,7 +3,7 @@ // Licensed under the BSD-3-Clause License (the "License"). // You may not use this file except in compliance with the License. -package cli_test +package cloud_test import ( "crypto/rand" From 17110a8072dcab501d748e746cd33f27dd99a85f Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 5 Sep 2024 18:59:34 +0300 Subject: [PATCH 08/28] fix(test): Remove instance after running test Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/instance_create_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/e2e/cloud/instance_create_test.go b/test/e2e/cloud/instance_create_test.go index bc4943171..d99ce0eb5 100644 --- a/test/e2e/cloud/instance_create_test.go +++ b/test/e2e/cloud/instance_create_test.go @@ -756,6 +756,28 @@ var _ = Describe("kraft cloud instance create", func() { ) }) + AfterEach(func() { + // Remove the instance after the test + cleanCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + cleanCmd.Args = append(cleanCmd.Args, + "cloud", "instance", "delete", + "--log-level", "info", + "--log-type", "json", + instanceNameFull, + ) + + err := cleanCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(cleanCmd.DumpError(stdout, stderr, err)) + } + + Expect(err).ToNot(HaveOccurred()) + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 1 instance\(s\)`)) + }) + It("should not error out with an API error", func() { err := cmd.Run() time.Sleep(2 * time.Second) From 44ce3ef1ebb31836cdcc5eec802ac90cb21574bd Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:35:29 +0300 Subject: [PATCH 09/28] feat(test): Add tests for 'cloud quotas' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/quotas_test.go | 147 ++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 test/e2e/cloud/quotas_test.go diff --git a/test/e2e/cloud/quotas_test.go b/test/e2e/cloud/quotas_test.go new file mode 100644 index 000000000..3b9638ceb --- /dev/null +++ b/test/e2e/cloud/quotas_test.go @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "fmt" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud quotas", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UKC_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UKC_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "quotas", "--log-level", "info", "--log-type", "json") + }) + + When("invoked without the json format", func() { + It("should list all quotas in json format", func() { + cmd.Args = append(cmd.Args, "-o", "json") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"user_uuid"`)) + }) + }) + + When("invoked without the table format", func() { + It("should list all quotas in the table format", func() { + cmd.Args = append(cmd.Args, "-o", "table") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`USER NAME`)) + }) + }) + + When("invoked without the list format", func() { + It("should list all metros in list format", func() { + cmd.Args = append(cmd.Args, "-o", "list") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`user name:`)) + }) + }) + + When("invoked without the raw format", func() { + It("should list all quotas in raw format", func() { + cmd.Args = append(cmd.Args, "-o", "raw") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"status":"success"`)) + Expect(stdout.String()).To(MatchRegexp(`"uuid"`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`View your resource quota on Unikraft Cloud`)) + }) + }) +}) From 1b7f496e73d86074d129d7624651552c6e76821d Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:35:41 +0300 Subject: [PATCH 10/28] feat(test): Add tests for 'cloud metro list' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/metro_list_test.go | 147 ++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 test/e2e/cloud/metro_list_test.go diff --git a/test/e2e/cloud/metro_list_test.go b/test/e2e/cloud/metro_list_test.go new file mode 100644 index 000000000..28ed36b0e --- /dev/null +++ b/test/e2e/cloud/metro_list_test.go @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "fmt" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud metro list", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UKC_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UKC_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "metro", "list", "--log-level", "info", "--log-type", "json") + }) + + When("invoked without the json format", func() { + It("should list all metros in json format", func() { + cmd.Args = append(cmd.Args, "-o", "json") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"code":"fra[0-9]+"`)) + }) + }) + + When("invoked without the table format", func() { + It("should list all metros in the table format", func() { + cmd.Args = append(cmd.Args, "-o", "table") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`CODE`)) + Expect(stdout.String()).To(MatchRegexp(`fra[0-9]+`)) + }) + }) + + When("invoked without the list format", func() { + It("should list all metros in list format", func() { + cmd.Args = append(cmd.Args, "-o", "list") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`code: fra[0-9]+`)) + }) + }) + + When("invoked with the status", func() { + It("should list all metros and their ping and status", func() { + cmd.Args = append(cmd.Args, "-o", "json", "-s") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"ping":"[0-9]+ MS"`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`List metros on`)) + }) + }) +}) From 343aae8c4ae37e03ac1c6034aed01d33413803b9 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:36:04 +0300 Subject: [PATCH 11/28] feat(test): Add tests for 'cloud volume attach' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_attach_test.go | 304 +++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 test/e2e/cloud/volume_attach_test.go diff --git a/test/e2e/cloud/volume_attach_test.go b/test/e2e/cloud/volume_attach_test.go new file mode 100644 index 000000000..8590bc081 --- /dev/null +++ b/test/e2e/cloud/volume_attach_test.go @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume attach", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-attach-test" + volumeName = "volume-attach-test" + instanceMemory = "64" + // TODO: Run one test without a service group also + instancePortMap = "443:8080" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "attach", "--log-level", "info", "--log-type", "json", "--at", "/mnt/test/volume") + }) + + When("invoked with json output and a name", func() { + var volumeNameFull string + var instanceNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createInstanceCmd1.Env = os.Environ() + createInstanceCmd1.Args = append(createInstanceCmd1.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "--port", instancePortMap, "--memory", "64", "--name", instanceNameFull, imageName) + + err = createInstanceCmd1.Run() + if err != nil { + fmt.Print(createInstanceCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + detachCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + detachCmd1.Env = os.Environ() + detachCmd1.Args = append(detachCmd1.Args, "cloud", "volume", "detach", "--log-level", "info", "--log-type", "json", volumeNameFull) + err := detachCmd1.Run() + if err != nil { + fmt.Print(detachCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceRmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRmCmd1.Env = os.Environ() + instanceRmCmd1.Args = append(instanceRmCmd1.Args, "cloud", "instance", "delete", "--log-level", "info", "--log-type", "json", instanceNameFull) + err = instanceRmCmd1.Run() + if err != nil { + fmt.Print(instanceRmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull) + err = rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should attach the volume to the instance", func() { + cmd.Args = append(cmd.Args, volumeNameFull, "--to", instanceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd1.Env = os.Environ() + getCmd1.Args = append(getCmd1.Args, "cloud", "volume", "get", "--log-level", "info", "--log-type", "json", "-o", "raw", volumeNameFull) + err = getCmd1.Run() + if err != nil { + fmt.Print(getCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"attached_to":"` + instanceNameFull + "\"")) + }) + }) + + When("invoked with json output and a name and the read-only flag", func() { + var volumeNameFull string + var instanceNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createInstanceCmd1.Env = os.Environ() + createInstanceCmd1.Args = append(createInstanceCmd1.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "--port", instancePortMap, "--memory", "64", "--name", instanceNameFull, imageName) + + err = createInstanceCmd1.Run() + if err != nil { + fmt.Print(createInstanceCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + detachCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + detachCmd1.Env = os.Environ() + detachCmd1.Args = append(detachCmd1.Args, "cloud", "volume", "detach", "--log-level", "info", "--log-type", "json", volumeNameFull) + err := detachCmd1.Run() + if err != nil { + fmt.Print(detachCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceRmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRmCmd1.Env = os.Environ() + instanceRmCmd1.Args = append(instanceRmCmd1.Args, "cloud", "instance", "delete", "--log-level", "info", "--log-type", "json", instanceNameFull) + err = instanceRmCmd1.Run() + if err != nil { + fmt.Print(instanceRmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull) + err = rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should attach the volume to the instance in read only mode", func() { + cmd.Args = append(cmd.Args, volumeNameFull, "-r", "--to", instanceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd1.Env = os.Environ() + getCmd1.Args = append(getCmd1.Args, "cloud", "volume", "get", "--log-level", "info", "--log-type", "json", "-o", "json", volumeNameFull) + err = getCmd1.Run() + if err != nil { + fmt.Print(getCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"attached_to":"` + instanceNameFull + "\"")) + Expect(stdout.String()).To(MatchRegexp(`"read_only":true"`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Attach a persistent volume to an instance`)) + }) + }) +}) From a136b7e2ff448e53334fe52bdde9012bb8a28994 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:36:17 +0300 Subject: [PATCH 12/28] feat(test): Add tests for 'cloud volume detach' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_detach_test.go | 307 +++++++++++++++++++++++++++ 1 file changed, 307 insertions(+) create mode 100644 test/e2e/cloud/volume_detach_test.go diff --git a/test/e2e/cloud/volume_detach_test.go b/test/e2e/cloud/volume_detach_test.go new file mode 100644 index 000000000..dee086f14 --- /dev/null +++ b/test/e2e/cloud/volume_detach_test.go @@ -0,0 +1,307 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume detach", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-attach-test" + volumeName = "volume-attach-test" + instanceMemory = "64" + // TODO: Run one test without a service group also + instancePortMap = "443:8080" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "detach", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with json output and a name", func() { + var volumeNameFull string + var instanceNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createInstanceCmd1.Env = os.Environ() + createInstanceCmd1.Args = append(createInstanceCmd1.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "--port", instancePortMap, "--memory", "64", "--name", instanceNameFull, imageName) + + err = createInstanceCmd1.Run() + if err != nil { + fmt.Print(createInstanceCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + attachInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + attachInstanceCmd1.Env = os.Environ() + attachInstanceCmd1.Args = append(attachInstanceCmd1.Args, "cloud", "volume", "attach", "--log-level", "info", "--log-type", "json", "--at", "/mnt/test/volume") + + attachInstanceCmd1.Args = append(attachInstanceCmd1.Args, volumeNameFull, "--to", instanceNameFull) + err = attachInstanceCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceRmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRmCmd1.Env = os.Environ() + instanceRmCmd1.Args = append(instanceRmCmd1.Args, "cloud", "instance", "delete", "--log-level", "info", "--log-type", "json", instanceNameFull) + err := instanceRmCmd1.Run() + if err != nil { + fmt.Print(instanceRmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull) + err = rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should detach the volume from the instance", func() { + cmd.Args = append(cmd.Args, volumeNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd1.Env = os.Environ() + getCmd1.Args = append(getCmd1.Args, "cloud", "volume", "get", "--log-level", "info", "--log-type", "json", "-o", "raw", volumeNameFull) + err = getCmd1.Run() + if err != nil { + fmt.Print(getCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(MatchRegexp(`"attached_to":"` + instanceNameFull + "\"")) + }) + }) + + When("invoked with json output and a name", func() { + var volumeNameFull string + var instanceNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createInstanceCmd1.Env = os.Environ() + createInstanceCmd1.Args = append(createInstanceCmd1.Args, "cloud", "instance", "create", "--log-level", "info", "--log-type", "json", "--port", instancePortMap, "--memory", "64", "--name", instanceNameFull, imageName) + + err = createInstanceCmd1.Run() + if err != nil { + fmt.Print(createInstanceCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + attachInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + attachInstanceCmd1.Env = os.Environ() + attachInstanceCmd1.Args = append(attachInstanceCmd1.Args, "cloud", "volume", "attach", "--log-level", "info", "--log-type", "json", "--at", "/mnt/test/volume") + + attachInstanceCmd1.Args = append(attachInstanceCmd1.Args, volumeNameFull, "--to", instanceNameFull) + err = attachInstanceCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceRmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRmCmd1.Env = os.Environ() + instanceRmCmd1.Args = append(instanceRmCmd1.Args, "cloud", "instance", "delete", "--log-level", "info", "--log-type", "json", instanceNameFull) + err := instanceRmCmd1.Run() + if err != nil { + fmt.Print(instanceRmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull) + err = rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should detach the volume from the instance", func() { + cmd.Args = append(cmd.Args, volumeNameFull, "--from", instanceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd1.Env = os.Environ() + getCmd1.Args = append(getCmd1.Args, "cloud", "volume", "get", "--log-level", "info", "--log-type", "json", "-o", "raw", volumeNameFull) + err = getCmd1.Run() + if err != nil { + fmt.Print(getCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(MatchRegexp(`"attached_to":"` + instanceNameFull + "\"")) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Detach a persistent volume from an instance`)) + }) + }) +}) From 4c04bd3fa7fcefb20a0643dffed82a9d55757678 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:36:32 +0300 Subject: [PATCH 13/28] feat(test): Add tests for 'cloud volume create' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_create_test.go | 255 +++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 test/e2e/cloud/volume_create_test.go diff --git a/test/e2e/cloud/volume_create_test.go b/test/e2e/cloud/volume_create_test.go new file mode 100644 index 000000000..5e403e7aa --- /dev/null +++ b/test/e2e/cloud/volume_create_test.go @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume create", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + volumeName = "volume-create-test" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with no flags", func() { + It("should error out with a kraftkit error", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).To(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`must specify --size flag`)) + }) + }) + + When("invoked with the size flag of unit 1", func() { + var volumeUUID string + + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--size", "1") + }) + + AfterEach(func() { + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = []string{"cloud", "volume", "delete", volumeUUID, "--log-level", "info", "--log-type", "json"} + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should create a volume of size 1Mi", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + volumeUUID = stdout.String() + }) + }) + + When("invoked with the size flag of unit 1Mi", func() { + var volumeUUID string + + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--size", "1Mi") + }) + + AfterEach(func() { + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = []string{"cloud", "volume", "delete", volumeUUID, "--log-level", "info", "--log-type", "json"} + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should create a volume of size 1Mi", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + volumeUUID = stdout.String() + }) + }) + + When("invoked with the size flag of unit 2M", func() { + var volumeUUID string + + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--size", "2M") + }) + + AfterEach(func() { + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = []string{"cloud", "volume", "delete", volumeUUID, "--log-level", "info", "--log-type", "json"} + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should create a volume of size 2M", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + volumeUUID = stdout.String() + }) + }) + + When("invoked with the size flag of unit 1Mi and a name", func() { + var volumeUUID string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull := fmt.Sprintf("%s-%d", volumeName, id) + + cmd.Args = append(cmd.Args, "--size", "1Mi", "--name", volumeNameFull) + }) + + AfterEach(func() { + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = []string{"cloud", "volume", "delete", volumeUUID, "--log-level", "info", "--log-type", "json"} + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should create a volume of size 1Mi", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + volumeUUID = stdout.String() + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Create a new persistent volume.`)) + }) + }) +}) From 1b6e8cb63918042f2602a072cfb9d21e4e2d796c Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:36:43 +0300 Subject: [PATCH 14/28] feat(test): Add tests for 'cloud volume delete' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_delete_test.go | 275 +++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 test/e2e/cloud/volume_delete_test.go diff --git a/test/e2e/cloud/volume_delete_test.go b/test/e2e/cloud/volume_delete_test.go new file mode 100644 index 000000000..bcb724a02 --- /dev/null +++ b/test/e2e/cloud/volume_delete_test.go @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume create", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + volumeName = "volume-delete-test" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with an UUID", func() { + var volumeUUID string + + BeforeEach(func() { + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1") + err := createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + volumeUUID = stdout.String() + volumeUUID = volumeUUID[:len(volumeUUID)-1] + }) + + It("should delete the instance", func() { + cmd.Args = append(cmd.Args, volumeUUID) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with a name", func() { + var volumeNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id) + + createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd.Env = os.Environ() + createCmd.Args = append(createCmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + err = createCmd.Run() + if err != nil { + fmt.Print(createCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should delete the instance", func() { + cmd.Args = append(cmd.Args, volumeNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with two names", func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should delete the instance", func() { + cmd.Args = append(cmd.Args, volumeNameFull1, volumeNameFull2) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with the '--all' flag", Serial, func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should delete all volumes", func() { + cmd.Args = append(cmd.Args, volumeNameFull1, volumeNameFull2) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`removing 2 volume`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Permanently delete persistent volume`)) + }) + }) +}) From 2f55d78beef2276c61c037567370962640b9bd18 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:37:03 +0300 Subject: [PATCH 15/28] feat(test): Add tests for 'cloud volume get' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_get_test.go | 362 ++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 test/e2e/cloud/volume_get_test.go diff --git a/test/e2e/cloud/volume_get_test.go b/test/e2e/cloud/volume_get_test.go new file mode 100644 index 000000000..0473fc3df --- /dev/null +++ b/test/e2e/cloud/volume_get_test.go @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume get", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + volumeName = "volume-get-test" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "get", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with json output and a name", func() { + var volumeNameFull1 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list 1 instance", func() { + cmd.Args = append(cmd.Args, "-o", "json", volumeNameFull1) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull1 + `"`)) + }) + }) + + When("invoked with list output and an UUID", func() { + var volumeNameFull1 string + var volumeUUID1 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + volumeUUID1 = stdout.String()[:len(stdout.String())-1] + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list 1 instance", func() { + cmd.Args = append(cmd.Args, "-o", "list", volumeUUID1) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + volumeNameFull1)) + }) + }) + + When("invoked with table output", func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd2.Env = os.Environ() + rmCmd2.Args = append(rmCmd2.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull2) + err = rmCmd2.Run() + if err != nil { + fmt.Print(rmCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list two instances", func() { + cmd.Args = append(cmd.Args, "-o", "table", volumeNameFull1, volumeNameFull2) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(volumeNameFull1)) + Expect(stdout.String()).To(MatchRegexp(volumeNameFull2)) + }) + }) + + When("invoked with raw output", func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd2.Env = os.Environ() + rmCmd2.Args = append(rmCmd2.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull2) + err = rmCmd2.Run() + if err != nil { + fmt.Print(rmCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list two instances", func() { + cmd.Args = append(cmd.Args, "-o", "raw", volumeNameFull1, volumeNameFull2) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull1 + `"`)) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull2 + `"`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Retrieve the state of persistent volumes`)) + }) + }) +}) From 7d99ea0ffc6948350d71c8ff23e19b22ed2d27ac Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 13 Sep 2024 17:37:20 +0300 Subject: [PATCH 16/28] feat(test): Add tests for 'cloud volume list' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_list_test.go | 424 +++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) create mode 100644 test/e2e/cloud/volume_list_test.go diff --git a/test/e2e/cloud/volume_list_test.go b/test/e2e/cloud/volume_list_test.go new file mode 100644 index 000000000..a9759ac54 --- /dev/null +++ b/test/e2e/cloud/volume_list_test.go @@ -0,0 +1,424 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume list", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + volumeName = "volume-list-test" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "list", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with json output", Serial, func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd2.Env = os.Environ() + rmCmd2.Args = append(rmCmd2.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull2) + err = rmCmd2.Run() + if err != nil { + fmt.Print(rmCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list two instances", func() { + cmd.Args = append(cmd.Args, "-o", "json") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull1 + `"`)) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull2 + `"`)) + }) + }) + + When("invoked with list output", Serial, func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd2.Env = os.Environ() + rmCmd2.Args = append(rmCmd2.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull2) + err = rmCmd2.Run() + if err != nil { + fmt.Print(rmCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list two instances", func() { + cmd.Args = append(cmd.Args, "-o", "list") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + volumeNameFull1)) + Expect(stdout.String()).To(MatchRegexp(`name: ` + volumeNameFull2)) + }) + }) + + When("invoked with table output", Serial, func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd2.Env = os.Environ() + rmCmd2.Args = append(rmCmd2.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull2) + err = rmCmd2.Run() + if err != nil { + fmt.Print(rmCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list two instances", func() { + cmd.Args = append(cmd.Args, "-o", "table") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(volumeNameFull1)) + Expect(stdout.String()).To(MatchRegexp(volumeNameFull2)) + }) + }) + + When("invoked with raw output", Serial, func() { + var volumeNameFull1 string + var volumeNameFull2 string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull1 = fmt.Sprintf("%s-%d", volumeName, id1) + + id2, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull2 = fmt.Sprintf("%s-%d", volumeName, id2) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd2.Env = os.Environ() + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + err = createCmd2.Run() + if err != nil { + fmt.Print(createCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull1) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd2.Env = os.Environ() + rmCmd2.Args = append(rmCmd2.Args, "cloud", "volume", "delete", "--log-level", "info", "--log-type", "json", volumeNameFull2) + err = rmCmd2.Run() + if err != nil { + fmt.Print(rmCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should list two instances", func() { + cmd.Args = append(cmd.Args, "-o", "raw") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull1 + `"`)) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + volumeNameFull2 + `"`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`List all volumes in your account`)) + }) + }) +}) From 29961f95b4a265f1b77fcf0348b17ead3959f166 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Tue, 17 Sep 2024 16:05:14 +0300 Subject: [PATCH 17/28] fix(test): Increase minimum volume size in tests Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/volume_attach_test.go | 4 ++-- test/e2e/cloud/volume_create_test.go | 20 ++++++++++---------- test/e2e/cloud/volume_delete_test.go | 12 ++++++------ test/e2e/cloud/volume_detach_test.go | 4 ++-- test/e2e/cloud/volume_get_test.go | 12 ++++++------ test/e2e/cloud/volume_list_test.go | 16 ++++++++-------- 6 files changed, 34 insertions(+), 34 deletions(-) diff --git a/test/e2e/cloud/volume_attach_test.go b/test/e2e/cloud/volume_attach_test.go index 8590bc081..65ca14cce 100644 --- a/test/e2e/cloud/volume_attach_test.go +++ b/test/e2e/cloud/volume_attach_test.go @@ -96,7 +96,7 @@ var _ = Describe("kraft cloud volume attach", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -197,7 +197,7 @@ var _ = Describe("kraft cloud volume attach", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) diff --git a/test/e2e/cloud/volume_create_test.go b/test/e2e/cloud/volume_create_test.go index 5e403e7aa..875243f93 100644 --- a/test/e2e/cloud/volume_create_test.go +++ b/test/e2e/cloud/volume_create_test.go @@ -90,11 +90,11 @@ var _ = Describe("kraft cloud volume create", func() { }) }) - When("invoked with the size flag of unit 1", func() { + When("invoked with the size flag of unit 8", func() { var volumeUUID string BeforeEach(func() { - cmd.Args = append(cmd.Args, "--size", "1") + cmd.Args = append(cmd.Args, "--size", "8") }) AfterEach(func() { @@ -111,7 +111,7 @@ var _ = Describe("kraft cloud volume create", func() { Expect(stdout.String()).ToNot(BeEmpty()) }) - It("should create a volume of size 1Mi", func() { + It("should create a volume of size 8Mi", func() { err := cmd.Run() if err != nil { fmt.Print(cmd.DumpError(stdout, stderr, err)) @@ -125,11 +125,11 @@ var _ = Describe("kraft cloud volume create", func() { }) }) - When("invoked with the size flag of unit 1Mi", func() { + When("invoked with the size flag of unit 8Mi", func() { var volumeUUID string BeforeEach(func() { - cmd.Args = append(cmd.Args, "--size", "1Mi") + cmd.Args = append(cmd.Args, "--size", "8Mi") }) AfterEach(func() { @@ -146,7 +146,7 @@ var _ = Describe("kraft cloud volume create", func() { Expect(stdout.String()).ToNot(BeEmpty()) }) - It("should create a volume of size 1Mi", func() { + It("should create a volume of size 8Mi", func() { err := cmd.Run() if err != nil { fmt.Print(cmd.DumpError(stdout, stderr, err)) @@ -160,11 +160,11 @@ var _ = Describe("kraft cloud volume create", func() { }) }) - When("invoked with the size flag of unit 2M", func() { + When("invoked with the size flag of unit 9M", func() { var volumeUUID string BeforeEach(func() { - cmd.Args = append(cmd.Args, "--size", "2M") + cmd.Args = append(cmd.Args, "--size", "9M") }) AfterEach(func() { @@ -181,7 +181,7 @@ var _ = Describe("kraft cloud volume create", func() { Expect(stdout.String()).ToNot(BeEmpty()) }) - It("should create a volume of size 2M", func() { + It("should create a volume of size 9M", func() { err := cmd.Run() if err != nil { fmt.Print(cmd.DumpError(stdout, stderr, err)) @@ -205,7 +205,7 @@ var _ = Describe("kraft cloud volume create", func() { } volumeNameFull := fmt.Sprintf("%s-%d", volumeName, id) - cmd.Args = append(cmd.Args, "--size", "1Mi", "--name", volumeNameFull) + cmd.Args = append(cmd.Args, "--size", "8Mi", "--name", volumeNameFull) }) AfterEach(func() { diff --git a/test/e2e/cloud/volume_delete_test.go b/test/e2e/cloud/volume_delete_test.go index bcb724a02..e0dfdcc0b 100644 --- a/test/e2e/cloud/volume_delete_test.go +++ b/test/e2e/cloud/volume_delete_test.go @@ -83,7 +83,7 @@ var _ = Describe("kraft cloud volume create", func() { BeforeEach(func() { createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd.Env = os.Environ() - createCmd.Args = append(createCmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1") + createCmd.Args = append(createCmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8") err := createCmd.Run() if err != nil { fmt.Print(createCmd.DumpError(stdout, stderr, err)) @@ -122,7 +122,7 @@ var _ = Describe("kraft cloud volume create", func() { createCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd.Env = os.Environ() - createCmd.Args = append(createCmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + createCmd.Args = append(createCmd.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull) err = createCmd.Run() if err != nil { fmt.Print(createCmd.DumpError(stdout, stderr, err)) @@ -165,7 +165,7 @@ var _ = Describe("kraft cloud volume create", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -177,7 +177,7 @@ var _ = Describe("kraft cloud volume create", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) @@ -220,7 +220,7 @@ var _ = Describe("kraft cloud volume create", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -232,7 +232,7 @@ var _ = Describe("kraft cloud volume create", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) diff --git a/test/e2e/cloud/volume_detach_test.go b/test/e2e/cloud/volume_detach_test.go index dee086f14..041a31b17 100644 --- a/test/e2e/cloud/volume_detach_test.go +++ b/test/e2e/cloud/volume_detach_test.go @@ -96,7 +96,7 @@ var _ = Describe("kraft cloud volume detach", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -199,7 +199,7 @@ var _ = Describe("kraft cloud volume detach", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) diff --git a/test/e2e/cloud/volume_get_test.go b/test/e2e/cloud/volume_get_test.go index 0473fc3df..6f571c03b 100644 --- a/test/e2e/cloud/volume_get_test.go +++ b/test/e2e/cloud/volume_get_test.go @@ -89,7 +89,7 @@ var _ = Describe("kraft cloud volume get", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -140,7 +140,7 @@ var _ = Describe("kraft cloud volume get", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -198,7 +198,7 @@ var _ = Describe("kraft cloud volume get", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -210,7 +210,7 @@ var _ = Describe("kraft cloud volume get", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) @@ -280,7 +280,7 @@ var _ = Describe("kraft cloud volume get", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -292,7 +292,7 @@ var _ = Describe("kraft cloud volume get", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) diff --git a/test/e2e/cloud/volume_list_test.go b/test/e2e/cloud/volume_list_test.go index a9759ac54..208396967 100644 --- a/test/e2e/cloud/volume_list_test.go +++ b/test/e2e/cloud/volume_list_test.go @@ -96,7 +96,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -108,7 +108,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) @@ -178,7 +178,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -190,7 +190,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) @@ -260,7 +260,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -272,7 +272,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) @@ -342,7 +342,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd1.Env = os.Environ() - createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull1) + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull1) err = createCmd1.Run() if err != nil { fmt.Print(createCmd1.DumpError(stdout, stderr, err)) @@ -354,7 +354,7 @@ var _ = Describe("kraft cloud volume list", func() { createCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) createCmd2.Env = os.Environ() - createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "1", "--name", volumeNameFull2) + createCmd2.Args = append(createCmd2.Args, "cloud", "volume", "create", "--log-level", "info", "--log-type", "json", "--size", "8", "--name", volumeNameFull2) err = createCmd2.Run() if err != nil { fmt.Print(createCmd2.DumpError(stdout, stderr, err)) From 650e49d63488f709691107c08bbaee1f72e32c80 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Tue, 17 Sep 2024 16:28:08 +0300 Subject: [PATCH 18/28] feat(test): Add tests for 'cloud volume import' Also add test fixtures for working with cpio archives. Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/fixtures/import/Dockerfile | 13 + .../fixtures/import/cpio-large/index.html | 1 + .../fixtures/import/cpio-large/soft-link-0 | 1 + .../fixtures/import/cpio-large/soft-link-1 | 1 + .../fixtures/import/cpio-large/soft-link-2 | 1 + .../fixtures/import/cpio-large/soft-link-3 | 1 + .../fixtures/import/cpio-large/soft-link-4 | 1 + .../fixtures/import/cpio-large/soft-link-5 | 1 + .../fixtures/import/cpio-large/soft-link-6 | 1 + .../fixtures/import/cpio-large/soft-link-7 | 1 + .../fixtures/import/cpio-large/soft-link-8 | 1 + .../fixtures/import/cpio-large/soft-link-9 | 1 + .../e2e/cloud/fixtures/import/cpio/index.html | 1 + test/e2e/cloud/volume_import_test.go | 612 ++++++++++++++++++ 14 files changed, 637 insertions(+) create mode 100644 test/e2e/cloud/fixtures/import/Dockerfile create mode 100644 test/e2e/cloud/fixtures/import/cpio-large/index.html create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-0 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-1 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-2 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-3 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-4 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-5 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-6 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-7 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-8 create mode 120000 test/e2e/cloud/fixtures/import/cpio-large/soft-link-9 create mode 100644 test/e2e/cloud/fixtures/import/cpio/index.html create mode 100644 test/e2e/cloud/volume_import_test.go diff --git a/test/e2e/cloud/fixtures/import/Dockerfile b/test/e2e/cloud/fixtures/import/Dockerfile new file mode 100644 index 000000000..47a3a4f52 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/Dockerfile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +# Licensed under the BSD-3-Clause License (the "License"). +# You may not use this file except in compliance with the License. + +FROM ubuntu:latest AS build + +RUN mkdir -p /tmp/build && \ + echo "

Hello World!

" > /tmp/build/hello.txt + +FROM scratch AS import + +COPY --from=build /tmp/build/hello.txt /index.html diff --git a/test/e2e/cloud/fixtures/import/cpio-large/index.html b/test/e2e/cloud/fixtures/import/cpio-large/index.html new file mode 100644 index 000000000..7e72fa1d6 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/index.html @@ -0,0 +1 @@ +

Hello World!

diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-0 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-0 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-0 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-1 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-1 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-1 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-2 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-2 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-2 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-3 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-3 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-3 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-4 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-4 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-4 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-5 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-5 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-5 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-6 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-6 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-6 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-7 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-7 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-7 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-8 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-8 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-8 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio-large/soft-link-9 b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-9 new file mode 120000 index 000000000..64233a9e9 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio-large/soft-link-9 @@ -0,0 +1 @@ +index.html \ No newline at end of file diff --git a/test/e2e/cloud/fixtures/import/cpio/index.html b/test/e2e/cloud/fixtures/import/cpio/index.html new file mode 100644 index 000000000..7e72fa1d6 --- /dev/null +++ b/test/e2e/cloud/fixtures/import/cpio/index.html @@ -0,0 +1 @@ +

Hello World!

diff --git a/test/e2e/cloud/volume_import_test.go b/test/e2e/cloud/volume_import_test.go new file mode 100644 index 000000000..fc9a45089 --- /dev/null +++ b/test/e2e/cloud/volume_import_test.go @@ -0,0 +1,612 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "io" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud volume import", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-import-test" + volumeName = "volume-import-test" + instanceMemory = "64" + // TODO: Run one test without a service group also + instancePortMap = "443:8080" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "volume", "import", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a volume name and a Dockerfile source", func() { + var volumeNameFull string + var instanceNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", + "--log-level", "info", "--log-type", "json", + "--size", "8", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createInstanceCmd1.Env = os.Environ() + createInstanceCmd1.Args = append(createInstanceCmd1.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--port", instancePortMap, "--memory", "64", + "--name", instanceNameFull, imageName) + + err = createInstanceCmd1.Run() + if err != nil { + fmt.Print(createInstanceCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + stopCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + stopCmd1.Env = os.Environ() + stopCmd1.Args = append(stopCmd1.Args, "cloud", "instance", "stop", + "--log-level", "info", "--log-type", "json", + instanceNameFull) + err := stopCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + detachCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + detachCmd1.Env = os.Environ() + detachCmd1.Args = append(detachCmd1.Args, "cloud", "volume", "detach", + "--log-level", "info", "--log-type", "json", + volumeNameFull) + err = detachCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd1.Env = os.Environ() + getCmd1.Args = append(getCmd1.Args, "cloud", "volume", "get", + "--log-level", "info", "--log-type", "json", + "-o", "raw", volumeNameFull) + err = getCmd1.Run() + if err != nil { + fmt.Print(getCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(MatchRegexp(`"attached_to":"` + instanceNameFull + "\"")) + + instanceRmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRmCmd1.Env = os.Environ() + instanceRmCmd1.Args = append(instanceRmCmd1.Args, "cloud", "instance", "delete", + "--log-level", "info", "--log-type", "json", + instanceNameFull) + err = instanceRmCmd1.Run() + if err != nil { + fmt.Print(instanceRmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", + "--log-level", "info", "--log-type", "json", + volumeNameFull) + err = rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should import files to the volume from the Dockerfile", func() { + cmd.Args = append(cmd.Args, "-v", volumeNameFull, "-s", "fixtures/import/Dockerfile") + time.Sleep(time.Second) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + attachInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + attachInstanceCmd1.Env = os.Environ() + attachInstanceCmd1.Args = append(attachInstanceCmd1.Args, "cloud", "volume", "attach", + "--log-level", "info", "--log-type", "json", + volumeNameFull, "--at", "/wwwroot", "--to", instanceNameFull) + err = attachInstanceCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + startCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + startCmd1.Env = os.Environ() + startCmd1.Args = append(startCmd1.Args, "cloud", "instance", "start", + "--log-level", "info", "--log-type", "json", + instanceNameFull) + err = startCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + time.Sleep(time.Second) + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Hello World!`)) + }) + }) + + When("invoked with a volume name and a directory source", func() { + var volumeNameFull string + var instanceNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", + "--log-level", "info", "--log-type", "json", + "--size", "8", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + createInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createInstanceCmd1.Env = os.Environ() + createInstanceCmd1.Args = append(createInstanceCmd1.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--port", instancePortMap, "--memory", "64", + "--name", instanceNameFull, imageName) + + err = createInstanceCmd1.Run() + if err != nil { + fmt.Print(createInstanceCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + stopCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + stopCmd1.Env = os.Environ() + stopCmd1.Args = append(stopCmd1.Args, "cloud", "instance", "stop", + "--log-level", "info", "--log-type", "json", + instanceNameFull) + err := stopCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + detachCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + detachCmd1.Env = os.Environ() + detachCmd1.Args = append(detachCmd1.Args, "cloud", "volume", "detach", + "--log-level", "info", "--log-type", "json", + volumeNameFull) + err = detachCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd1.Env = os.Environ() + getCmd1.Args = append(getCmd1.Args, "cloud", "volume", "get", + "--log-level", "info", "--log-type", "json", + "-o", "raw", volumeNameFull) + err = getCmd1.Run() + if err != nil { + fmt.Print(getCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(MatchRegexp(`"attached_to":"` + instanceNameFull + "\"")) + + instanceRmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRmCmd1.Env = os.Environ() + instanceRmCmd1.Args = append(instanceRmCmd1.Args, "cloud", "instance", "delete", + "--log-level", "info", "--log-type", "json", + instanceNameFull) + err = instanceRmCmd1.Run() + if err != nil { + fmt.Print(instanceRmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", + "--log-level", "info", "--log-type", "json", + volumeNameFull) + err = rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should import files to the volume from the cpio file", func() { + cmd.Args = append(cmd.Args, "-v", volumeNameFull, "-s", "fixtures/import/cpio") + err := cmd.Run() + time.Sleep(time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + attachInstanceCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + attachInstanceCmd1.Env = os.Environ() + attachInstanceCmd1.Args = append(attachInstanceCmd1.Args, "cloud", "volume", "attach", + "--log-level", "info", "--log-type", "json", + volumeNameFull, "--at", "/wwwroot", "--to", instanceNameFull) + err = attachInstanceCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + startCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + startCmd1.Env = os.Environ() + startCmd1.Args = append(startCmd1.Args, "cloud", "instance", "start", + "--log-level", "info", "--log-type", "json", + instanceNameFull) + err = startCmd1.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + time.Sleep(time.Second) + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Hello World!`)) + }) + }) + + When("invoked with a volume name and a directory source and the '--force' flag", func() { + var volumeNameFull string + var content string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", + "--log-level", "info", "--log-type", "json", + "--size", "9", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + file, err := os.OpenFile("fixtures/import/cpio-large/index.html", os.O_RDWR, 0o644) + if err != nil { + panic(err) + } + + buf := make([]byte, 20) + _, err = file.Read(buf) + if err != nil { + panic(err) + } + + content = string(buf) + for i := 0; i < 50000; i++ { + _, err = io.WriteString(file, content) + if err != nil { + panic(err) + } + } + + err = file.Close() + if err != nil { + panic(err) + } + }) + + AfterEach(func() { + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", + "--log-level", "info", "--log-type", "json", + volumeNameFull) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + file, err := os.OpenFile("fixtures/import/cpio-large/index.html", os.O_WRONLY, 0o644) + if err != nil { + panic(err) + } + + err = file.Truncate(0) + if err != nil { + panic(err) + } + + _, err = file.WriteString(content) + if err != nil { + panic(err) + } + + err = file.Close() + if err != nil { + panic(err) + } + }) + + It("should import files to the volume from the cpio file regardless of size", func() { + cmd.Args = append(cmd.Args, "-v", volumeNameFull, "-s", "fixtures/import/cpio-large", "--force") + err := cmd.Run() + time.Sleep(time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with a volume name and a url source", func() { + var volumeNameFull string + + BeforeEach(func() { + id1, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + volumeNameFull = fmt.Sprintf("%s-%d", volumeName, id1) + + createCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + createCmd1.Env = os.Environ() + createCmd1.Args = append(createCmd1.Args, "cloud", "volume", "create", + "--log-level", "info", "--log-type", "json", + "--size", "128", "--name", volumeNameFull) + err = createCmd1.Run() + if err != nil { + fmt.Print(createCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + rmCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + rmCmd1.Env = os.Environ() + rmCmd1.Args = append(rmCmd1.Args, "cloud", "volume", "delete", + "--log-level", "info", "--log-type", "json", + volumeNameFull) + err := rmCmd1.Run() + if err != nil { + fmt.Print(rmCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should import files to the volume from the docker link", func() { + cmd.Args = append(cmd.Args, "-v", volumeNameFull, "-s", "ubuntu:noble-20240827.1") + err := cmd.Run() + time.Sleep(time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Import local data to a persistent volume`)) + }) + }) +}) From 1c5b7a90325ff5ef72910c90201ca9e3e7680fe0 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Wed, 18 Sep 2024 18:21:52 +0300 Subject: [PATCH 19/28] feat(test): Add tests for 'cloud service create' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/service_create_test.go | 555 ++++++++++++++++++++++++++ 1 file changed, 555 insertions(+) create mode 100644 test/e2e/cloud/service_create_test.go diff --git a/test/e2e/cloud/service_create_test.go b/test/e2e/cloud/service_create_test.go new file mode 100644 index 000000000..5b6eb43aa --- /dev/null +++ b/test/e2e/cloud/service_create_test.go @@ -0,0 +1,555 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud service create", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-create-test" + serviceName = "service-create-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "service", "create", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a name and default parameters", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should attach the instance to the service and work", func() { + cmd.Args = append(cmd.Args, "--name", serviceNameFull, "443:8080/tls+http") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a name, a subdomain and default parameters", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should attach the instance to the service and work", func() { + cmd.Args = append(cmd.Args, + "--name", serviceNameFull, + "--subdomain", "test-"+serviceNameFull, + "443:8080/tls+http") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + Expect(url).To(MatchRegexp(`https://test-` + serviceNameFull + `.`)) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a name, two subdomains and default parameters", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should attach the instance to the service and work", func() { + cmd.Args = append(cmd.Args, + "--name", serviceNameFull, + "--subdomain", "test-1-"+serviceNameFull, + "--subdomain", "test-2-"+serviceNameFull, + "443:8080/tls+http") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + + urls := strings.SplitN(url, ",", 2) + Expect(urls).To(HaveLen(2)) + + // Run the "curl" command to test the url on the first subdomain + url = urls[0] + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + + // Run the "curl" command to test the url on the second subdomain + url = "https://" + urls[1] + curlCmd = fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a name, soft and hard limits, and default parameters", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should attach the instance to the service and work", func() { + cmd.Args = append(cmd.Args, + "--name", serviceNameFull, + "--soft-limit", "1", + "--hard-limit", "2", + "443:8080/tls+http") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a name and multiple parameters", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should attach the instance to the service and work", func() { + cmd.Args = append(cmd.Args, + "--name", serviceNameFull, + "8081:8081/tls", + "443:8080/tls+http") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + url := urlParser(stdout) + Expect(url).ToNot(BeEmpty()) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, url) + + err = curlCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Create a service`)) + }) + }) +}) From d93f52a4e3e3ce13e6724f320a78deaecd072036 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 19 Sep 2024 12:03:10 +0300 Subject: [PATCH 20/28] feat(test): Add tests for 'cloud service list' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/service_list_test.go | 433 ++++++++++++++++++++++++++++ 1 file changed, 433 insertions(+) create mode 100644 test/e2e/cloud/service_list_test.go diff --git a/test/e2e/cloud/service_list_test.go b/test/e2e/cloud/service_list_test.go new file mode 100644 index 000000000..132efebca --- /dev/null +++ b/test/e2e/cloud/service_list_test.go @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud service list", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-list-test" + serviceName = "service-list-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "service", "list", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with the json output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in json format", func() { + cmd.Args = append(cmd.Args, "-o", "json") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + serviceNameFull + `"`)) + Expect(stdout.String()).To(MatchRegexp(`"instances":"` + instanceNameFull + `"`)) + }) + }) + + When("invoked with the table output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in table format", func() { + cmd.Args = append(cmd.Args, "-o", "table") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("NAME")) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + }) + }) + + When("invoked with the list output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in list format", func() { + cmd.Args = append(cmd.Args, "-o", "list") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`instances: ` + instanceNameFull)) + }) + }) + + When("invoked with the yaml output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in yaml format", func() { + cmd.Args = append(cmd.Args, "-o", "list") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`instances: ` + instanceNameFull)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`List services`)) + }) + }) +}) From 8fd72b3d10219e79051715aee96fe7e970ac82b8 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 19 Sep 2024 12:27:38 +0300 Subject: [PATCH 21/28] feat(test): Add tests for 'cloud service get' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/service_get_test.go | 535 +++++++++++++++++++++++++++++ 1 file changed, 535 insertions(+) create mode 100644 test/e2e/cloud/service_get_test.go diff --git a/test/e2e/cloud/service_get_test.go b/test/e2e/cloud/service_get_test.go new file mode 100644 index 000000000..4ba3f530a --- /dev/null +++ b/test/e2e/cloud/service_get_test.go @@ -0,0 +1,535 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud service get", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-get-test" + serviceName = "service-get-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "service", "get", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with the json output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in json format", func() { + cmd.Args = append(cmd.Args, "-o", "json", serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + serviceNameFull + `"`)) + Expect(stdout.String()).To(MatchRegexp(`"instances":"` + instanceNameFull + `"`)) + }) + }) + + When("invoked with the table output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in table format", func() { + cmd.Args = append(cmd.Args, "-o", "table", serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp("NAME")) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(instanceNameFull)) + }) + }) + + When("invoked with the list output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in list format", func() { + cmd.Args = append(cmd.Args, "-o", "list", serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`instances: ` + instanceNameFull)) + }) + }) + + When("invoked with the yaml output format", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in yaml format", func() { + cmd.Args = append(cmd.Args, "-o", "list", serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`instances: ` + instanceNameFull)) + }) + }) + + When("invoked with the yaml output format and two services", func() { + var instanceNameFull string + var serviceNameFull1 string + var serviceNameFull2 string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull1 = fmt.Sprintf("%s-%d-1", serviceName, id) + serviceNameFull2 = fmt.Sprintf("%s-%d-2", serviceName, id) + + serviceCreateCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd1.Env = os.Environ() + serviceCreateCmd1.Args = append(serviceCreateCmd1.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull1, + "443:8080/tls+http") + + err = serviceCreateCmd1.Run() + if err != nil { + fmt.Print(serviceCreateCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + serviceCreateCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd2.Env = os.Environ() + serviceCreateCmd2.Args = append(serviceCreateCmd2.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull2, + "443:8080/tls+http") + + err = serviceCreateCmd2.Run() + if err != nil { + fmt.Print(serviceCreateCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull2, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd1.Env = os.Environ() + serviceDeleteCmd1.Args = append(serviceDeleteCmd1.Args, "cloud", "service", "delete", serviceNameFull1, serviceNameFull2) + err = serviceDeleteCmd1.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("list the created service with it's instance in yaml format", func() { + cmd.Args = append(cmd.Args, "-o", "list", serviceNameFull1, serviceNameFull2) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull1)) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull2)) + Expect(stdout.String()).To(MatchRegexp(`instances: ` + instanceNameFull)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Retrieve the state of services`)) + }) + }) +}) From b434c742a78d25905d05a2576a6b12e64242c4a7 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 19 Sep 2024 14:36:43 +0300 Subject: [PATCH 22/28] feat(test): Add tests for 'cloud service remove' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/service_remove_test.go | 503 ++++++++++++++++++++++++++ 1 file changed, 503 insertions(+) create mode 100644 test/e2e/cloud/service_remove_test.go diff --git a/test/e2e/cloud/service_remove_test.go b/test/e2e/cloud/service_remove_test.go new file mode 100644 index 000000000..07b78a937 --- /dev/null +++ b/test/e2e/cloud/service_remove_test.go @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud service remove", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-remove-test" + serviceName = "service-remove-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "service", "delete", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a single empty service", func() { + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should remove the service", func() { + cmd.Args = append(cmd.Args, serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "service", "get", "-o", "json", serviceNameFull) + + err = getCmd.Run() + Expect(err).To(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with two empty services", func() { + var serviceNameFull1 string + var serviceNameFull2 string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + serviceNameFull1 = fmt.Sprintf("%s-%d-1", serviceName, id) + serviceNameFull2 = fmt.Sprintf("%s-%d-2", serviceName, id) + + serviceCreateCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd1.Env = os.Environ() + serviceCreateCmd1.Args = append(serviceCreateCmd1.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull1, + "443:8080/tls+http") + + err = serviceCreateCmd1.Run() + if err != nil { + fmt.Print(serviceCreateCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + serviceCreateCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd2.Env = os.Environ() + serviceCreateCmd2.Args = append(serviceCreateCmd2.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull2, + "443:8080/tls+http") + + err = serviceCreateCmd2.Run() + if err != nil { + fmt.Print(serviceCreateCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should remove the services", func() { + cmd.Args = append(cmd.Args, serviceNameFull1, serviceNameFull2) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "service", "get", "-o", "json", serviceNameFull1, serviceNameFull2) + + err = getCmd.Run() + Expect(err).To(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with a single service with instances attached", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should error out when removing", func() { + cmd.Args = append(cmd.Args, serviceNameFull) + err := cmd.Run() + Expect(err).To(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "service", "get", "-o", "json", serviceNameFull) + + err = getCmd.Run() + if err != nil { + fmt.Print(getCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with no arguments and the '--all' flag", Serial, func() { + var instanceNameFull string + var serviceNameFull1 string + var serviceNameFull2 string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull1 = fmt.Sprintf("%s-%d-1", serviceName, id) + serviceNameFull2 = fmt.Sprintf("%s-%d-2", serviceName, id) + + serviceCreateCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd1.Env = os.Environ() + serviceCreateCmd1.Args = append(serviceCreateCmd1.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull1, + "443:8080/tls+http") + + err = serviceCreateCmd1.Run() + if err != nil { + fmt.Print(serviceCreateCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + serviceCreateCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd2.Env = os.Environ() + serviceCreateCmd2.Args = append(serviceCreateCmd2.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull2, + "443:8080/tls+http") + + err = serviceCreateCmd2.Run() + if err != nil { + fmt.Print(serviceCreateCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull1, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull1) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should remove all created services and ignore attached ones", func() { + cmd.Args = append(cmd.Args, "--all") + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + lsCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + lsCmd.Env = os.Environ() + lsCmd.Args = append(lsCmd.Args, "cloud", "service", "list", "-o", "json") + + err = lsCmd.Run() + if err != nil { + fmt.Print(lsCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`"name":"` + serviceNameFull1 + `"`)) + Expect(stdout.String()).To(MatchRegexp(`ignoring 1 service`)) + }) + }) + + When("invoked with a single service and the '--wait-empty' flag", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Env = os.Environ() + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, + "443:8080/tls+http") + + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err = instanceDeleteCmd.Run() + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("remove the service after no instances are attached anymore", func() { + cmd.Args = append(cmd.Args, "--wait-empty", serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + getCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + getCmd.Env = os.Environ() + getCmd.Args = append(getCmd.Args, "cloud", "service", "get", "-o", "json", serviceNameFull) + + err = getCmd.Run() + Expect(err).To(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Delete services`)) + }) + }) +}) From b6c61d5affd2926f44493415e78cf48987d8be6e Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Thu, 19 Sep 2024 15:21:25 +0300 Subject: [PATCH 23/28] feat(test): Add tests for 'cloud tunnel' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/tunnel_test.go | 718 ++++++++++++++++++++++++++++++++++ 1 file changed, 718 insertions(+) create mode 100644 test/e2e/cloud/tunnel_test.go diff --git a/test/e2e/cloud/tunnel_test.go b/test/e2e/cloud/tunnel_test.go new file mode 100644 index 000000000..736790557 --- /dev/null +++ b/test/e2e/cloud/tunnel_test.go @@ -0,0 +1,718 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +func parsePrivateIP(stdout *fcmd.IOStream) string { + if strings.Contains(stdout.String(), "\"private_ip\"") { + ip := strings.SplitN(stdout.String(), "private_ip\":\"", 2)[1] + ip = strings.SplitN(ip, "\"", 2)[0] + if ip == "" { + return "" + } + return ip + } + + return "" +} + +var _ = Describe("kraft cloud tunnel", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-tunnel-test" + instanceMemory = "64" + internalPort = "8080" + localPortStart = 8000 + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "tunnel", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a single, contracted, instance", Serial, func() { + var instanceNameFull string + var localPort string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + randPort, err := rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceRemoveCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd.Env = os.Environ() + instanceRemoveCmd.Args = append(instanceRemoveCmd.Args, "cloud", "instance", "remove", instanceNameFull) + + err = instanceRemoveCmd.Run() + if err != nil { + fmt.Print(instanceRemoveCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should allow connection to the instance", func() { + startCurl := make(chan struct{}, 1) + go func() { + cmd.Args = append(cmd.Args, localPort+":"+instanceNameFull+":"+internalPort) + startCurl <- struct{}{} + _ = cmd.Run() + }() + + <-startCurl + time.Sleep(time.Second) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort) + + err := curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a single, uncontracted, instance", Serial, func() { + var instanceNameFull string + var localPort string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + randPort, err := rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceRemoveCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd.Env = os.Environ() + instanceRemoveCmd.Args = append(instanceRemoveCmd.Args, "cloud", "instance", "remove", instanceNameFull) + + err = instanceRemoveCmd.Run() + if err != nil { + fmt.Print(instanceRemoveCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should allow connection to the instance", func() { + startCurl := make(chan struct{}, 1) + go func() { + cmd.Args = append(cmd.Args, localPort+":"+instanceNameFull+":"+internalPort+"/tcp") + startCurl <- struct{}{} + _ = cmd.Run() + }() + + <-startCurl + time.Sleep(time.Second) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort) + + err := curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a single, contracted, internal FQDN", Serial, func() { + var instanceNameFull string + var localPort string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + randPort, err := rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceRemoveCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd.Env = os.Environ() + instanceRemoveCmd.Args = append(instanceRemoveCmd.Args, "cloud", "instance", "remove", instanceNameFull) + + err = instanceRemoveCmd.Run() + if err != nil { + fmt.Print(instanceRemoveCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should allow connection to the instance", func() { + startCurl := make(chan struct{}, 1) + go func() { + cmd.Args = append(cmd.Args, localPort+":"+instanceNameFull+".internal"+":"+internalPort) + startCurl <- struct{}{} + _ = cmd.Run() + }() + + <-startCurl + time.Sleep(time.Second) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort) + + err := curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with a single, contracted, private ip", Serial, func() { + var instanceNameFull string + var instancePrivateIP string + var localPort string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + randPort, err := rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instancePrivateIP = parsePrivateIP(stdout) + Expect(instancePrivateIP).ToNot(BeEmpty()) + }) + + AfterEach(func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceRemoveCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd.Env = os.Environ() + instanceRemoveCmd.Args = append(instanceRemoveCmd.Args, "cloud", "instance", "remove", instanceNameFull) + + err = instanceRemoveCmd.Run() + if err != nil { + fmt.Print(instanceRemoveCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should allow connection to the instance", func() { + startCurl := make(chan struct{}, 1) + go func() { + cmd.Args = append(cmd.Args, localPort+":"+instancePrivateIP+":"+internalPort) + startCurl <- struct{}{} + _ = cmd.Run() + }() + + <-startCurl + time.Sleep(time.Second) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort) + + err := curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with two, uncontracted, instances", Serial, func() { + var instanceNameFull1 string + var localPort1 string + var instanceNameFull2 string + var localPort2 string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull1 = fmt.Sprintf("%s-%d-1", instanceName, id) + instanceNameFull2 = fmt.Sprintf("%s-%d-2", instanceName, id) + + randPort, err := rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort1 = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + randPort, err = rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort2 = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + instanceCreateCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd1.Env = os.Environ() + instanceCreateCmd1.Args = append(instanceCreateCmd1.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", instanceNameFull1, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd1.Run() + if err != nil { + fmt.Print(instanceCreateCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceCreateCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd2.Env = os.Environ() + instanceCreateCmd2.Args = append(instanceCreateCmd2.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", instanceNameFull2, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd2.Run() + if err != nil { + fmt.Print(instanceCreateCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceRemoveCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd1.Env = os.Environ() + instanceRemoveCmd1.Args = append(instanceRemoveCmd1.Args, "cloud", "instance", "remove", instanceNameFull1) + + err = instanceRemoveCmd1.Run() + if err != nil { + fmt.Print(instanceRemoveCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + instanceRemoveCmd2 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd2.Env = os.Environ() + instanceRemoveCmd2.Args = append(instanceRemoveCmd2.Args, "cloud", "instance", "remove", instanceNameFull2) + + err = instanceRemoveCmd2.Run() + if err != nil { + fmt.Print(instanceRemoveCmd2.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should allow connection to the instance", func() { + startCurl := make(chan struct{}, 1) + go func() { + cmd.Args = append(cmd.Args, + localPort1+":"+instanceNameFull1+":"+internalPort+"/tcp", + localPort2+":"+instanceNameFull2+":"+internalPort+"/tcp") + startCurl <- struct{}{} + _ = cmd.Run() + }() + + <-startCurl + time.Sleep(time.Second) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort1) + + err := curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + + // Run the "curl" command to test the url + curlCmd = fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort2) + + err = curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with one, uncontracted, instance and custom control ports", Serial, func() { + var instanceNameFull string + var localPort string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + + randPort, err := rand.Int(rand.Reader, big.NewInt(999)) + if err != nil { + panic(err) + } + localPort = fmt.Sprintf("%d", localPortStart+int(randPort.Int64())) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + imageName) + + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + err := cmd.Process.Kill() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + err = cmd.Process.Release() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceRemoveCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceRemoveCmd.Env = os.Environ() + instanceRemoveCmd.Args = append(instanceRemoveCmd.Args, "cloud", "instance", "remove", instanceNameFull) + + err = instanceRemoveCmd.Run() + if err != nil { + fmt.Print(instanceRemoveCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + It("should allow connection to the instance", func() { + startCurl := make(chan struct{}, 1) + go func() { + cmd.Args = append(cmd.Args, + "--tunnel-control-port", "5443", + "--tunnel-proxy-port", "5444", + localPort+":"+instanceNameFull+":"+internalPort+"/tcp") + startCurl <- struct{}{} + _ = cmd.Run() + }() + + <-startCurl + time.Sleep(time.Second) + + // Run the "curl" command to test the url + curlCmd := fcmd.NewCurl(stdout, stderr) + curlCmd.Args = append(curlCmd.Args, "http://localhost:"+localPort) + + err := curlCmd.Run() + if err != nil { + fmt.Print(curlCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Welcome to nginx!`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Forward a local port to an unexposed instance`)) + }) + }) +}) From c810041fcd273b875fcaba910854b01aea9ba8d1 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 20 Sep 2024 16:39:00 +0300 Subject: [PATCH 24/28] feat(test): Add tests for 'cloud scale init' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/scale_init_test.go | 207 ++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 test/e2e/cloud/scale_init_test.go diff --git a/test/e2e/cloud/scale_init_test.go b/test/e2e/cloud/scale_init_test.go new file mode 100644 index 000000000..e6b36c8b4 --- /dev/null +++ b/test/e2e/cloud/scale_init_test.go @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud scale init", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-init-test" + serviceName = "service-init-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "scale", "init", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with all flags", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", + "--name", serviceNameFull, "443:8080/tls+http") + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + scaleResetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleResetCmd.Env = os.Environ() + scaleResetCmd.Args = append(scaleResetCmd.Args, "cloud", "scale", "reset", serviceNameFull) + err := scaleResetCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(scaleResetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err = instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should initialize an autoscale configuration", func() { + cmd.Args = append(cmd.Args, "--master", instanceNameFull, "--min-size", "2", "--max-size", "10", "--cooldown-time", "13s", "--warmup-time", "26s", serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleGetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleGetCmd.Env = os.Environ() + scaleGetCmd.Args = append(scaleGetCmd.Args, "cloud", "scale", "get", serviceNameFull, "-o", "list") + err = scaleGetCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(scaleGetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`enabled: true`)) + Expect(stdout.String()).To(MatchRegexp(`min size: 2`)) + Expect(stdout.String()).To(MatchRegexp(`max size: 10`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Initialize autoscale configuration for a service`)) + }) + }) +}) From bcca44bfd0655f2e3f8c8e5af42c210caea9c20e Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 20 Sep 2024 16:39:22 +0300 Subject: [PATCH 25/28] feat(test): Add tests for 'cloud scale add' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/scale_add_test.go | 256 +++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 test/e2e/cloud/scale_add_test.go diff --git a/test/e2e/cloud/scale_add_test.go b/test/e2e/cloud/scale_add_test.go new file mode 100644 index 000000000..f0b347a09 --- /dev/null +++ b/test/e2e/cloud/scale_add_test.go @@ -0,0 +1,256 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +func serviceUUIDParser(stdout *fcmd.IOStream) string { + if strings.Contains(stdout.String(), "\"uuid\"") { + uuid := strings.SplitN(stdout.String(), "uuid\":\"", 2)[1] + uuid = strings.SplitN(uuid, "\"", 2)[0] + if uuid == "" { + return "" + } + return uuid + } + + return "" +} + +var _ = Describe("kraft cloud scale add", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-add-test" + serviceName = "service-add-test" + policyName = "policy-add-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "scale", "add", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a policy inside a configuration", func() { + var instanceNameFull string + var serviceNameFull string + var policyNameFull1 string + var serviceUUID string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + policyNameFull1 = fmt.Sprintf("%s-%d-1", policyName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, "443:8080/tls+http") + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + // Extract the service UUID + serviceUUID = serviceUUIDParser(stdout) + Expect(serviceUUID).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleInitCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleInitCmd.Args = append(scaleInitCmd.Args, "cloud", "scale", "init", + "--master", instanceNameFull, + "--min-size", "2", + "--max-size", "10", + "--cooldown-time", "13s", + "--warmup-time", "26s", + serviceNameFull) + err = scaleInitCmd.Run() + if err != nil { + fmt.Print(scaleInitCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + scaleRemoveCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleRemoveCmd1.Env = os.Environ() + scaleRemoveCmd1.Args = append(scaleRemoveCmd1.Args, "cloud", "scale", "remove", serviceUUID, policyNameFull1) + err := scaleRemoveCmd1.Run() + if err != nil { + fmt.Print(scaleRemoveCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + scaleResetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleResetCmd.Env = os.Environ() + scaleResetCmd.Args = append(scaleResetCmd.Args, "cloud", "scale", "reset", serviceNameFull) + err = scaleResetCmd.Run() + if err != nil { + fmt.Print(scaleResetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err = instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should add the policy to the configuration", func() { + cmd.Args = append(cmd.Args, serviceNameFull, "--name", policyNameFull1, "--step", "0:10/1", "--step", "10:20/2") + err := cmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleGetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleGetCmd.Env = os.Environ() + scaleGetCmd.Args = append(scaleGetCmd.Args, "cloud", "scale", "get", serviceNameFull, "-o", "list") + err = scaleGetCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(scaleGetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`enabled: true`)) + Expect(stdout.String()).To(MatchRegexp(`min size: 2`)) + Expect(stdout.String()).To(MatchRegexp(`max size: 10`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).To(MatchRegexp(policyNameFull1)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Add an autoscale configuration policy for a service`)) + }) + }) +}) From 6fa251e4c492ed0c168ef8f7b6db6000261ca333 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 20 Sep 2024 16:39:33 +0300 Subject: [PATCH 26/28] feat(test): Add tests for 'cloud scale remove' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/scale_remove_test.go | 242 ++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 test/e2e/cloud/scale_remove_test.go diff --git a/test/e2e/cloud/scale_remove_test.go b/test/e2e/cloud/scale_remove_test.go new file mode 100644 index 000000000..92b9d0a0d --- /dev/null +++ b/test/e2e/cloud/scale_remove_test.go @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud scale remove", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-remove-test" + serviceName = "service-remove-test" + policyName = "policy-remove-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "scale", "remove", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a policy to remove", func() { + var instanceNameFull string + var serviceNameFull string + var policyNameFull1 string + var serviceUUID string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + policyNameFull1 = fmt.Sprintf("%s-%d", policyName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, "443:8080/tls+http") + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + // Extract the service UUID + serviceUUID = serviceUUIDParser(stdout) + Expect(serviceUUID).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleInitCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleInitCmd.Args = append(scaleInitCmd.Args, "cloud", "scale", "init", + "--master", instanceNameFull, + "--min-size", "2", + "--max-size", "10", + "--cooldown-time", "13s", + "--warmup-time", "26s", + serviceNameFull) + err = scaleInitCmd.Run() + if err != nil { + fmt.Print(scaleInitCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleAddCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleAddCmd.Env = os.Environ() + scaleAddCmd.Args = append(scaleAddCmd.Args, "cloud", "scale", "add", serviceNameFull, "--name", policyNameFull1, "--step", "0:10/1", "--step", "10:20/2") + err = scaleAddCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + AfterEach(func() { + scaleResetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleResetCmd.Env = os.Environ() + scaleResetCmd.Args = append(scaleResetCmd.Args, "cloud", "scale", "reset", serviceNameFull) + err := scaleResetCmd.Run() + if err != nil { + fmt.Print(scaleResetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err = instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should remove the policy from the configuration", func() { + cmd.Args = append(cmd.Args, serviceUUID, policyNameFull1) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleGetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleGetCmd.Env = os.Environ() + scaleGetCmd.Args = append(scaleGetCmd.Args, "cloud", "scale", "get", serviceNameFull, "-o", "list") + err = scaleGetCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(scaleGetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`enabled: true`)) + Expect(stdout.String()).To(MatchRegexp(`min size: 2`)) + Expect(stdout.String()).To(MatchRegexp(`max size: 10`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).ToNot(MatchRegexp(policyNameFull1)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Delete an autoscale configuration policy`)) + }) + }) +}) From 729f2567e32a1593a0b24ab9ba55132b28033f4d Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 20 Sep 2024 16:39:41 +0300 Subject: [PATCH 27/28] feat(test): Add tests for 'cloud scale reset' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/scale_reset_test.go | 209 +++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 test/e2e/cloud/scale_reset_test.go diff --git a/test/e2e/cloud/scale_reset_test.go b/test/e2e/cloud/scale_reset_test.go new file mode 100644 index 000000000..fce4769b8 --- /dev/null +++ b/test/e2e/cloud/scale_reset_test.go @@ -0,0 +1,209 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud scale reset", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-reset-test" + serviceName = "service-reset-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "scale", "reset", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a configured autoscale configuration", func() { + var instanceNameFull string + var serviceNameFull string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", + "--name", serviceNameFull, "443:8080/tls+http") + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleInitCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleInitCmd.Env = os.Environ() + scaleInitCmd.Args = append(scaleInitCmd.Args, "cloud", "scale", "init", + "--master", instanceNameFull, + "--min-size", "2", + "--max-size", "10", + "--cooldown-time", "13s", + "--warmup-time", "26s", + serviceNameFull) + err = scaleInitCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(scaleInitCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + AfterEach(func() { + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err := instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should initialize an autoscale configuration", func() { + cmd.Args = append(cmd.Args, serviceNameFull) + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleGetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleGetCmd.Env = os.Environ() + scaleGetCmd.Args = append(scaleGetCmd.Args, "cloud", "scale", "get", serviceNameFull, "-o", "list") + err = scaleGetCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(scaleGetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`enabled: false`)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Reset autoscale configuration of a service`)) + }) + }) +}) From 032156f126f5c6892c2a00f2a8638b2f96bfd647 Mon Sep 17 00:00:00 2001 From: Cezar Craciunoiu Date: Fri, 20 Sep 2024 16:40:22 +0300 Subject: [PATCH 28/28] feat(test): Add tests for 'cloud scale get' Signed-off-by: Cezar Craciunoiu --- test/e2e/cloud/scale_get_test.go | 242 +++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 test/e2e/cloud/scale_get_test.go diff --git a/test/e2e/cloud/scale_get_test.go b/test/e2e/cloud/scale_get_test.go new file mode 100644 index 000000000..13c8797a2 --- /dev/null +++ b/test/e2e/cloud/scale_get_test.go @@ -0,0 +1,242 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. + +package cloud_test + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "time" + + . "github.com/onsi/ginkgo/v2" //nolint:stylecheck + . "github.com/onsi/gomega" //nolint:stylecheck + + fcmd "kraftkit.sh/test/e2e/framework/cmd" + fcfg "kraftkit.sh/test/e2e/framework/config" +) + +var _ = Describe("kraft cloud scale get", func() { + var cmd *fcmd.Cmd + + var stdout *fcmd.IOStream + var stderr *fcmd.IOStream + + var cfg *fcfg.Config + + const ( + imageName = "nginx:latest" + instanceName = "instance-get-test" + serviceName = "service-get-test" + policyName = "policy-get-test" + instanceMemory = "64" + ) + + BeforeEach(func() { + token := os.Getenv("UNIKRAFTCLOUD_TOKEN") + + if token == "" { + token = os.Getenv("KRAFTCLOUD_TOKEN") + } + + if token == "" { + token = os.Getenv("KC_TOKEN") + } + + if token == "" { + token = os.Getenv("UKC_TOKEN") + } + + if token == "" { + Skip("UNIKRAFTCLOUD_TOKEN is not set") + } + + metro := os.Getenv("UNIKRAFTCLOUD_METRO") + + if metro == "" { + metro = os.Getenv("KRAFTCLOUD_METRO") + } + + if metro == "" { + metro = os.Getenv("KC_METRO") + } + + if metro == "" { + metro = os.Getenv("UKC_METRO") + } + + if metro == "" { + Skip("UNIKRAFTCLOUD_METRO is not set") + } + + stdout = fcmd.NewIOStream() + stderr = fcmd.NewIOStream() + + cfg = fcfg.NewTempConfig() + + cmd = fcmd.NewKraft(stdout, stderr, cfg.Path()) + cmd.Env = os.Environ() + cmd.Args = append(cmd.Args, "cloud", "scale", "get", "--log-level", "info", "--log-type", "json") + }) + + When("invoked with a policy inside a configuration and the list output", func() { + var instanceNameFull string + var serviceNameFull string + var policyNameFull1 string + var serviceUUID string + + BeforeEach(func() { + id, err := rand.Int(rand.Reader, big.NewInt(100000000000)) + if err != nil { + panic(err) + } + instanceNameFull = fmt.Sprintf("%s-%d", instanceName, id) + serviceNameFull = fmt.Sprintf("%s-%d", serviceName, id) + policyNameFull1 = fmt.Sprintf("%s-%d-1", policyName, id) + + serviceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceCreateCmd.Args = append(serviceCreateCmd.Args, "cloud", "service", "create", + "--log-level", "info", "--log-type", "json", "-o", "json", + "--name", serviceNameFull, "443:8080/tls+http") + err = serviceCreateCmd.Run() + if err != nil { + fmt.Print(serviceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(serviceNameFull)) + + // Extract the service UUID + serviceUUID = serviceUUIDParser(stdout) + Expect(serviceUUID).ToNot(BeEmpty()) + + instanceCreateCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceCreateCmd.Env = os.Environ() + instanceCreateCmd.Args = append(instanceCreateCmd.Args, "cloud", "instance", "create", + "-o", "json", "--log-level", "info", "--log-type", "json", + "--name", instanceNameFull, + "--memory", instanceMemory, + "--start", + "--service", serviceNameFull, + imageName) + err = instanceCreateCmd.Run() + if err != nil { + fmt.Print(instanceCreateCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleInitCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleInitCmd.Args = append(scaleInitCmd.Args, "cloud", "scale", "init", + "--master", instanceNameFull, + "--min-size", "2", + "--max-size", "10", + "--cooldown-time", "13s", + "--warmup-time", "26s", + serviceNameFull) + err = scaleInitCmd.Run() + if err != nil { + fmt.Print(scaleInitCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + + scaleAddCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleAddCmd.Env = os.Environ() + scaleAddCmd.Args = append(scaleAddCmd.Args, "cloud", "scale", "add", serviceNameFull, "--name", policyNameFull1, "--step", "0:10/1", "--step", "10:20/2") + err = scaleAddCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).ToNot(BeEmpty()) + }) + + AfterEach(func() { + scaleRemoveCmd1 := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleRemoveCmd1.Env = os.Environ() + scaleRemoveCmd1.Args = append(scaleRemoveCmd1.Args, "cloud", "scale", "remove", serviceUUID, policyNameFull1) + err := scaleRemoveCmd1.Run() + if err != nil { + fmt.Print(scaleRemoveCmd1.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + scaleResetCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + scaleResetCmd.Env = os.Environ() + scaleResetCmd.Args = append(scaleResetCmd.Args, "cloud", "scale", "reset", serviceNameFull) + err = scaleResetCmd.Run() + if err != nil { + fmt.Print(scaleResetCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + instanceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + instanceDeleteCmd.Env = os.Environ() + instanceDeleteCmd.Args = append(instanceDeleteCmd.Args, "cloud", "instance", "delete", instanceNameFull) + err = instanceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(instanceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + serviceDeleteCmd := fcmd.NewKraft(stdout, stderr, cfg.Path()) + serviceDeleteCmd.Env = os.Environ() + serviceDeleteCmd.Args = append(serviceDeleteCmd.Args, "cloud", "service", "delete", serviceNameFull) + err = serviceDeleteCmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(serviceDeleteCmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + }) + + It("should print the configuration in list format", func() { + cmd.Args = append(cmd.Args, serviceNameFull, "-o", "list") + err := cmd.Run() + time.Sleep(2 * time.Second) + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`name: ` + serviceNameFull)) + Expect(stdout.String()).To(MatchRegexp(`enabled: true`)) + Expect(stdout.String()).To(MatchRegexp(`min size: 2`)) + Expect(stdout.String()).To(MatchRegexp(`max size: 10`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).To(MatchRegexp(`26000`)) + Expect(stdout.String()).To(MatchRegexp(policyNameFull1)) + }) + }) + + When("invoked with the --help flag", func() { + BeforeEach(func() { + cmd.Args = append(cmd.Args, "--help") + }) + + It("should print the command's help", func() { + err := cmd.Run() + if err != nil { + fmt.Print(cmd.DumpError(stdout, stderr, err)) + } + Expect(err).ToNot(HaveOccurred()) + + Expect(stderr.String()).To(BeEmpty()) + Expect(stdout.String()).To(MatchRegexp(`Get an autoscale configuration or policy of a service`)) + }) + }) +})