diff --git a/test/e2e/combined_test.go b/test/e2e/combined_test.go index d3d131a90..91c1143bb 100644 --- a/test/e2e/combined_test.go +++ b/test/e2e/combined_test.go @@ -7,6 +7,7 @@ import ( "os" "path" "strconv" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -44,7 +45,7 @@ func TestCombined(t *testing.T) { require.NoError(t, err) serverName := withSuffix("test-server") - serverID, err := createServer(t, serverName, TestServerType, TestImage, "--ssh-key", strconv.FormatInt(sshKeyID, 10), "--network", strconv.FormatInt(networkID, 10)) + serverID, err := createServer(t, serverName, TestServerType, TestImageName, "--ssh-key", strconv.FormatInt(sshKeyID, 10), "--network", strconv.FormatInt(networkID, 10)) require.NoError(t, err) firewallName := withSuffix("test-firewall") @@ -230,6 +231,82 @@ func TestCombined(t *testing.T) { assert.Empty(t, out) }) + t.Run("image", func(t *testing.T) { + var id int64 + + t.Run("create-image", func(t *testing.T) { + out, err := runCommand(t, "server", "create-image", strconv.FormatInt(serverID, 10), "--type", "snapshot") + require.NoError(t, err) + assert.Regexp(t, `^Image [0-9]+ created from Server [0-9]+\n$`, out) + + id, err = strconv.ParseInt(out[6:strings.Index(out, " created")], 10, 64) + require.NoError(t, err) + }) + + t.Run("update", func(t *testing.T) { + out, err := runCommand(t, "image", "update", strconv.FormatInt(id, 10), "--description", "This is a test image") + require.NoError(t, err) + assert.Equal(t, fmt.Sprintf("Image %d updated\n", id), out) + }) + + t.Run("add-label", func(t *testing.T) { + out, err := runCommand(t, "image", "add-label", strconv.FormatInt(id, 10), "foo=bar") + require.NoError(t, err) + assert.Equal(t, fmt.Sprintf("Label(s) foo added to Image %d\n", id), out) + }) + + t.Run("enable-protection", func(t *testing.T) { + out, err := runCommand(t, "image", "enable-protection", strconv.FormatInt(id, 10), "delete") + require.NoError(t, err) + assert.Equal(t, fmt.Sprintf("Resource protection enabled for Image %d\n", id), out) + }) + + t.Run("describe", func(t *testing.T) { + out, err := runCommand(t, "image", "describe", strconv.FormatInt(id, 10)) + require.NoError(t, err) + assert.Regexp(t, + NewRegex().Start(). + Lit("ID:").Whitespace().Int().Newline(). + Lit("Type:").Whitespace().Lit("snapshot").Newline(). + Lit("Status:").Whitespace().Lit("available").Newline(). + Lit("Name:").Whitespace().Lit("-").Newline(). + Lit("Created:").Whitespace().UnixDate().Lit(" (").HumanizeTime().Lit(")").Newline(). + Lit("Description:").Whitespace().Lit("This is a test image").Newline(). + Lit("Image size:").Whitespace().FileSize().Newline(). + Lit("Disk size:").Whitespace().FileSize().Newline(). + Lit("OS flavor:").Whitespace().Identifier().Newline(). + Lit("OS version:").Whitespace().Lit("-").Newline(). + Lit("Architecture:").Whitespace().OneOfLit("x86", "arm").Newline(). + Lit("Rapid deploy:").Whitespace().Lit("no").Newline(). + Lit("Protection:").Newline(). + Lit(" Delete:").Whitespace().Lit("yes").Newline(). + Lit("Labels:").Newline(). + Lit(" foo: bar").Newline(). + End(), + out, + ) + }) + + t.Run("delete-protected", func(t *testing.T) { + out, err := runCommand(t, "image", "delete", strconv.FormatInt(id, 10)) + require.Error(t, err) + assert.Regexp(t, `^snapshot deletion is protected \(protected, [0-9a-f]+\)$`, err.Error()) + assert.Empty(t, out) + }) + + t.Run("disable-protection", func(t *testing.T) { + out, err := runCommand(t, "image", "disable-protection", strconv.FormatInt(id, 10), "delete") + require.NoError(t, err) + assert.Equal(t, fmt.Sprintf("Resource protection disabled for Image %d\n", id), out) + }) + + t.Run("delete-image", func(t *testing.T) { + out, err := runCommand(t, "image", "delete", strconv.FormatInt(id, 10)) + require.NoError(t, err) + assert.Equal(t, fmt.Sprintf("Image %d deleted\n", id), out) + }) + }) + t.Run("delete-server", func(t *testing.T) { out, err := runCommand(t, "server", "delete", strconv.FormatInt(serverID, 10)) require.NoError(t, err) diff --git a/test/e2e/image_test.go b/test/e2e/image_test.go new file mode 100644 index 000000000..569acde0c --- /dev/null +++ b/test/e2e/image_test.go @@ -0,0 +1,83 @@ +//go:build e2e + +package e2e + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestImage(t *testing.T) { + t.Parallel() + + t.Run("list", func(t *testing.T) { + t.Run("table", func(t *testing.T) { + out, err := runCommand(t, "image", "list") + require.NoError(t, err) + + assert.Regexp(t, + NewRegex().Start(). + SeparatedByWhitespace("ID", "TYPE", "NAME", "DESCRIPTION", "ARCHITECTURE", "IMAGE SIZE", "DISK SIZE", "CREATED", "DEPRECATED").OptionalWhitespace().Newline(). + AnyTimes( + NewRegex(). + Int().Whitespace(). + OneOfLit("system", "app", "snapshot", "backup").Whitespace(). + Identifier().Whitespace(). + AnyString().Whitespace(). + OneOfLit("x86", "arm").Whitespace(). + OneOf("-", NewRegex().FileSize()).Whitespace(). + FileSize().Whitespace(). + UnixDate().Whitespace(). + OneOf("-", NewRegex().UnixDate()). + OptionalWhitespace().Newline(), + ). + End(), + out, + ) + }) + + t.Run("json", func(t *testing.T) { + out, err := runCommand(t, "image", "list", "-o=json") + require.NoError(t, err) + require.NoError(t, json.Unmarshal([]byte(out), new([]any))) + }) + }) + + t.Run("describe", func(t *testing.T) { + t.Run("non-existing", func(t *testing.T) { + out, err := runCommand(t, "image", "describe", "non-existing-image", "--architecture=x86") + require.EqualError(t, err, "Image not found: non-existing-image") + assert.Empty(t, out) + }) + + t.Run("normal", func(t *testing.T) { + out, err := runCommand(t, "image", "describe", TestImageID) + require.NoError(t, err) + + assert.Regexp(t, + NewRegex().Start(). + Lit("ID:").Whitespace().Int().Newline(). + Lit("Type:").Whitespace().OneOfLit("system", "app", "snapshot", "backup").Newline(). + Lit("Status:").Whitespace().OneOfLit("available", "creating", "unavailable").Newline(). + Lit("Name:").Whitespace().Identifier().Newline(). + Lit("Created:").Whitespace().UnixDate().Lit(" (").HumanizeTime().Lit(")").Newline(). + Lit("Description:").Whitespace().AnyString().Newline(). + Lit("Image size:").Whitespace().OneOf("-", NewRegex().FileSize()).Newline(). + Lit("Disk size:").Whitespace().FileSize().Newline(). + Lit("OS flavor:").Whitespace().Identifier().Newline(). + Lit("OS version:").Whitespace().Identifier().Newline(). + Lit("Architecture:").Whitespace().OneOfLit("x86", "arm").Newline(). + Lit("Rapid deploy:").Whitespace().OneOfLit("yes", "no").Newline(). + Lit("Protection:").Newline(). + Lit(" Delete:").Whitespace().OneOfLit("yes", "no").Newline(). + Lit("Labels:").Newline(). + Lit(" No labels").Newline(). + End(), + out, + ) + }) + }) +} diff --git a/test/e2e/variables.go b/test/e2e/variables.go index 30f5cab77..8da66da49 100644 --- a/test/e2e/variables.go +++ b/test/e2e/variables.go @@ -9,8 +9,8 @@ import ( ) var ( - // TestImage is the system image that is used in end-to-end tests. - TestImage = getEnv("TEST_IMAGE", "ubuntu-24.04") + // TestImageName is the name of the system image that is used in end-to-end tests. + TestImageName = getEnv("TEST_IMAGE", "ubuntu-24.04") // TestImageID is the system image ID that is used in end-to-end tests. TestImageID = getEnv("TEST_IMAGE_ID", "161547269")