From 93d60346bad7683841b856269daa5090147d00eb Mon Sep 17 00:00:00 2001 From: Samuel K Date: Wed, 13 May 2026 15:29:55 -0500 Subject: [PATCH] test(e2e): expand Podman provider e2e test coverage Add build, lifecycle command, agent delivery, exec, and cleanup tests for both rootless and rootful Podman contexts. Tests reuse existing docker testdata and follow the same framework patterns as provider_docker.go. --- e2e/tests/up/provider_podman.go | 294 +++++++++++++++++++++++++++++--- 1 file changed, 273 insertions(+), 21 deletions(-) diff --git a/e2e/tests/up/provider_podman.go b/e2e/tests/up/provider_podman.go index f994696d6..b903c9cba 100644 --- a/e2e/tests/up/provider_podman.go +++ b/e2e/tests/up/provider_podman.go @@ -4,9 +4,11 @@ import ( "context" "os" "os/exec" + "strings" "github.com/devsy-org/devsy/e2e/framework" "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" ) var _ = ginkgo.Describe( @@ -30,17 +32,142 @@ var _ = ginkgo.Describe( framework.ExpectNoError(err) }) - ginkgo.It( - "should start a new workspace with existing image", - func(ctx context.Context) { - tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) - framework.ExpectNoError(err) + ginkgo.Context("basic", func() { + ginkgo.It( + "should start a new workspace with existing image", + func(ctx context.Context) { + tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) + framework.ExpectNoError(err) - err = f.DevsyUp(ctx, tempDir) - framework.ExpectNoError(err) - }, - ginkgo.SpecTimeout(framework.TimeoutShort()), - ) + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("build", func() { + ginkgo.It( + "should start a workspace with a multistage Dockerfile build", + func(ctx context.Context) { + tempDir, err := setupWorkspace( + "tests/up/testdata/docker-with-multi-stage-build", + initialDir, + f, + ) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutLong()), + ) + + ginkgo.It( + "should build and respect overrideCommand false", + func(ctx context.Context) { + tempDir, err := setupWorkspace( + "tests/up/testdata/docker-override-command-false", + initialDir, + f, + ) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("lifecycle commands", func() { + ginkgo.It( + "should run postCreateCommand with object syntax", + func(ctx context.Context) { + tempDir, err := setupWorkspace( + "tests/up/testdata/docker-postcreate-parallel", + initialDir, + f, + ) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + one, err := f.DevsySSH(ctx, tempDir, "cat /tmp/post-create-one.out") + framework.ExpectNoError(err) + gomega.Expect(strings.TrimSpace(one)).To(gomega.Equal("postCreateOne")) + + two, err := f.DevsySSH(ctx, tempDir, "cat /tmp/post-create-two.out") + framework.ExpectNoError(err) + gomega.Expect(strings.TrimSpace(two)).To(gomega.Equal("postCreateTwo")) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("agent delivery", func() { + ginkgo.It( + "should deliver the agent binary and execute SSH commands", + func(ctx context.Context) { + tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + err = f.DevsySSHEchoTestString(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("exec", func() { + ginkgo.It( + "should execute commands inside the container via SSH", + func(ctx context.Context) { + tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + out, err := f.DevsySSH(ctx, tempDir, "echo -n hello-podman") + framework.ExpectNoError(err) + framework.ExpectEqual(out, "hello-podman") + + out, err = f.DevsySSH(ctx, tempDir, "pwd") + framework.ExpectNoError(err) + gomega.Expect(strings.TrimSpace(out)).NotTo(gomega.BeEmpty()) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("cleanup", func() { + ginkgo.It( + "should delete workspace and clean up resources", + func(ctx context.Context) { + tempDir, err := framework.CopyToTempDir("tests/up/testdata/docker") + framework.ExpectNoError(err) + ginkgo.DeferCleanup(framework.CleanupTempDir, initialDir, tempDir) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + _, err = f.FindWorkspace(ctx, tempDir) + framework.ExpectNoError(err) + + err = f.DevsyWorkspaceDelete(ctx, tempDir) + framework.ExpectNoError(err) + + _, err = f.FindWorkspace(ctx, tempDir) + framework.ExpectError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) }) ginkgo.Context("with rootful podman", func() { @@ -59,7 +186,7 @@ var _ = ginkgo.Describe( err = wrapper.Close() framework.ExpectNoError(err) - // #nosec G302 -- TODO Consider using a more secure permission setting and ownership if needed. + // #nosec G302 -- wrapper script needs execute permission err = os.Chmod(initialDir+"/bin/podman-rootful", 0o755) framework.ExpectNoError(err) @@ -74,17 +201,142 @@ var _ = ginkgo.Describe( framework.ExpectNoError(err) }) - ginkgo.It( - "should start a new workspace with existing image", - func(ctx context.Context) { - tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) - framework.ExpectNoError(err) + ginkgo.Context("basic", func() { + ginkgo.It( + "should start a new workspace with existing image", + func(ctx context.Context) { + tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) + framework.ExpectNoError(err) - err = f.DevsyUp(ctx, tempDir) - framework.ExpectNoError(err) - }, - ginkgo.SpecTimeout(framework.TimeoutShort()), - ) + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("build", func() { + ginkgo.It( + "should start a workspace with a multistage Dockerfile build", + func(ctx context.Context) { + tempDir, err := setupWorkspace( + "tests/up/testdata/docker-with-multi-stage-build", + initialDir, + f, + ) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutLong()), + ) + + ginkgo.It( + "should build and respect overrideCommand false", + func(ctx context.Context) { + tempDir, err := setupWorkspace( + "tests/up/testdata/docker-override-command-false", + initialDir, + f, + ) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("lifecycle commands", func() { + ginkgo.It( + "should run postCreateCommand with object syntax", + func(ctx context.Context) { + tempDir, err := setupWorkspace( + "tests/up/testdata/docker-postcreate-parallel", + initialDir, + f, + ) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + one, err := f.DevsySSH(ctx, tempDir, "cat /tmp/post-create-one.out") + framework.ExpectNoError(err) + gomega.Expect(strings.TrimSpace(one)).To(gomega.Equal("postCreateOne")) + + two, err := f.DevsySSH(ctx, tempDir, "cat /tmp/post-create-two.out") + framework.ExpectNoError(err) + gomega.Expect(strings.TrimSpace(two)).To(gomega.Equal("postCreateTwo")) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("agent delivery", func() { + ginkgo.It( + "should deliver the agent binary and execute SSH commands", + func(ctx context.Context) { + tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + err = f.DevsySSHEchoTestString(ctx, tempDir) + framework.ExpectNoError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("exec", func() { + ginkgo.It( + "should execute commands inside the container via SSH", + func(ctx context.Context) { + tempDir, err := setupWorkspace("tests/up/testdata/docker", initialDir, f) + framework.ExpectNoError(err) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + out, err := f.DevsySSH(ctx, tempDir, "echo -n hello-podman") + framework.ExpectNoError(err) + framework.ExpectEqual(out, "hello-podman") + + out, err = f.DevsySSH(ctx, tempDir, "pwd") + framework.ExpectNoError(err) + gomega.Expect(strings.TrimSpace(out)).NotTo(gomega.BeEmpty()) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) + + ginkgo.Context("cleanup", func() { + ginkgo.It( + "should delete workspace and clean up resources", + func(ctx context.Context) { + tempDir, err := framework.CopyToTempDir("tests/up/testdata/docker") + framework.ExpectNoError(err) + ginkgo.DeferCleanup(framework.CleanupTempDir, initialDir, tempDir) + + err = f.DevsyUp(ctx, tempDir) + framework.ExpectNoError(err) + + _, err = f.FindWorkspace(ctx, tempDir) + framework.ExpectNoError(err) + + err = f.DevsyWorkspaceDelete(ctx, tempDir) + framework.ExpectNoError(err) + + _, err = f.FindWorkspace(ctx, tempDir) + framework.ExpectError(err) + }, + ginkgo.SpecTimeout(framework.TimeoutShort()), + ) + }) }) }, )