From da1246d58747c596627a082be82c34414a0c598f Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Tue, 29 Aug 2023 13:38:31 -0600 Subject: [PATCH 1/3] CI: e2e: fetch the standard system-test image Finally, after so many years, let's start using testimage:YYYYMMDD. Use it in place of LABELS_IMAGE, which nothing/nowhere was using. Signed-off-by: Ed Santiago --- test/e2e/config_amd64.go | 4 ++-- test/e2e/config_arm64.go | 4 ++-- test/e2e/config_ppc64le.go | 4 ++-- test/e2e/images_test.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/test/e2e/config_amd64.go b/test/e2e/config_amd64.go index 469809de80..64b27e830d 100644 --- a/test/e2e/config_amd64.go +++ b/test/e2e/config_amd64.go @@ -5,11 +5,11 @@ var ( STORAGE_OPTIONS = "--storage-driver vfs" //nolint:revive,stylecheck ROOTLESS_STORAGE_FS = "vfs" //nolint:revive,stylecheck ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs" //nolint:revive,stylecheck - CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, REGISTRY_IMAGE, INFRA_IMAGE, LABELS_IMAGE, HEALTHCHECK_IMAGE, SYSTEMD_IMAGE, fedoraToolbox} //nolint:revive,stylecheck + CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, REGISTRY_IMAGE, INFRA_IMAGE, CITEST_IMAGE, HEALTHCHECK_IMAGE, SYSTEMD_IMAGE, fedoraToolbox} //nolint:revive,stylecheck NGINX_IMAGE = "quay.io/libpod/alpine_nginx:latest" //nolint:revive,stylecheck BB_GLIBC = "docker.io/library/busybox:glibc" //nolint:revive,stylecheck REGISTRY_IMAGE = "quay.io/libpod/registry:2.8.2" //nolint:revive,stylecheck - LABELS_IMAGE = "quay.io/libpod/alpine_labels:latest" //nolint:revive,stylecheck + CITEST_IMAGE = "quay.io/libpod/testimage:20221018" //nolint:revive,stylecheck SYSTEMD_IMAGE = "quay.io/libpod/systemd-image:20230106" //nolint:revive,stylecheck CIRROS_IMAGE = "quay.io/libpod/cirros:latest" //nolint:revive,stylecheck ) diff --git a/test/e2e/config_arm64.go b/test/e2e/config_arm64.go index 3c80e7668a..8dc0ebe12a 100644 --- a/test/e2e/config_arm64.go +++ b/test/e2e/config_arm64.go @@ -5,11 +5,11 @@ var ( STORAGE_OPTIONS = "--storage-driver vfs" //nolint:revive,stylecheck ROOTLESS_STORAGE_FS = "vfs" //nolint:revive,stylecheck ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs" //nolint:revive,stylecheck - CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, REGISTRY_IMAGE, INFRA_IMAGE, LABELS_IMAGE, HEALTHCHECK_IMAGE, SYSTEMD_IMAGE, fedoraToolbox} //nolint:revive,stylecheck + CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, REGISTRY_IMAGE, INFRA_IMAGE, CITEST_IMAGE, HEALTHCHECK_IMAGE, SYSTEMD_IMAGE, fedoraToolbox} //nolint:revive,stylecheck NGINX_IMAGE = "quay.io/lsm5/alpine_nginx-aarch64:latest" //nolint:revive,stylecheck BB_GLIBC = "docker.io/library/busybox:glibc" //nolint:revive,stylecheck REGISTRY_IMAGE = "quay.io/libpod/registry:2.8.2" //nolint:revive,stylecheck - LABELS_IMAGE = "quay.io/libpod/alpine_labels:latest" //nolint:revive,stylecheck + CITEST_IMAGE = "quay.io/libpod/testimage:20221018" //nolint:revive,stylecheck SYSTEMD_IMAGE = "quay.io/libpod/systemd-image:20230106" //nolint:revive,stylecheck CIRROS_IMAGE = "quay.io/libpod/cirros:latest" //nolint:revive,stylecheck ) diff --git a/test/e2e/config_ppc64le.go b/test/e2e/config_ppc64le.go index a4bec748a3..63d8a50498 100644 --- a/test/e2e/config_ppc64le.go +++ b/test/e2e/config_ppc64le.go @@ -5,9 +5,9 @@ var ( STORAGE_OPTIONS = "--storage-driver overlay" ROOTLESS_STORAGE_FS = "vfs" ROOTLESS_STORAGE_OPTIONS = "--storage-driver vfs" - CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, INFRA_IMAGE, LABELS_IMAGE} + CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, INFRA_IMAGE, CITEST_IMAGE} NGINX_IMAGE = "quay.io/libpod/alpine_nginx-ppc64le:latest" BB_GLIBC = "docker.io/ppc64le/busybox:glibc" - LABELS_IMAGE = "quay.io/libpod/alpine_labels-ppc64le:latest" + CITEST_IMAGE = "quay.io/libpod/testimage:20221018" REGISTRY_IMAGE string ) diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go index 7beca4c3e5..9098b400df 100644 --- a/test/e2e/images_test.go +++ b/test/e2e/images_test.go @@ -127,7 +127,7 @@ var _ = Describe("Podman images", func() { retalpine := podmanTest.Podman([]string{"images", "-f", "reference=*lpine*"}) retalpine.WaitWithDefaultTimeout() Expect(retalpine).Should(Exit(0)) - Expect(retalpine.OutputToStringArray()).To(HaveLen(6)) + Expect(retalpine.OutputToStringArray()).To(HaveLen(5)) Expect(retalpine.OutputToString()).To(ContainSubstring("alpine")) retalpine = podmanTest.Podman([]string{"images", "-f", "reference=alpine"}) From 6cbd17c0f4e5d6ddc47c8400a2a53a4dfc000ae0 Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Tue, 29 Aug 2023 13:48:51 -0600 Subject: [PATCH 2/3] CI: e2e: new ginkgo matcher, ExitCleanly() Combined test for (exitcode == 0) && (nothing on stderr). Returns more useful diagnostic messages than the default: old: Expected N to equal 0 new: Command failed with exit status N new: Unexpected warnings seen on stderr: "...." Signed-off-by: Ed Santiago --- test/utils/matchers.go | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/utils/matchers.go b/test/utils/matchers.go index c56bd55c38..da40dba20d 100644 --- a/test/utils/matchers.go +++ b/test/utils/matchers.go @@ -168,6 +168,57 @@ func (matcher *ExitMatcher) MatchMayChangeInTheFuture(actual interface{}) bool { return true } +// ExitCleanly asserts that a PodmanSession exits 0 and with no stderr +func ExitCleanly() types.GomegaMatcher { + return &exitCleanlyMatcher{} +} + +type exitCleanlyMatcher struct { + msg string +} + +type podmanSession interface { + ExitCode() int + ErrorToString() string +} + +func (matcher *exitCleanlyMatcher) Match(actual interface{}) (success bool, err error) { + session, ok := actual.(podmanSession) + if !ok { + return false, fmt.Errorf("ExitCleanly must be passed a PodmanSession; Got:\n %+v\n%q", actual, format.Object(actual, 1)) + } + + exitcode := session.ExitCode() + stderr := session.ErrorToString() + if exitcode != 0 { + matcher.msg = fmt.Sprintf("Command failed with exit status %d", exitcode) + if stderr != "" { + matcher.msg += ". See above for error message." + } + return false, nil + } + + // FIXME: #19809, "failed to connect to syslog" warnings on f38 + // FIXME: so, until that is fixed, don't check stderr if containerized + if !Containerized() { + if stderr != "" { + matcher.msg = fmt.Sprintf("Unexpected warnings seen on stderr: %q", stderr) + return false, nil + } + } + + return true, nil +} + +func (matcher *exitCleanlyMatcher) FailureMessage(_ interface{}) (message string) { + return matcher.msg +} + +func (matcher *exitCleanlyMatcher) NegatedFailureMessage(_ interface{}) (message string) { + // FIXME - I see no situation in which we could ever want this? + return matcher.msg + " (NOT!)" +} + type ValidJSONMatcher struct { types.GomegaMatcher } From 4082b67f6eaba513953c0d020f491995e22df721 Mon Sep 17 00:00:00 2001 From: Ed Santiago Date: Tue, 29 Aug 2023 13:53:22 -0600 Subject: [PATCH 3/3] CI: e2e: first use of new ExitCleanly() matcher A nearly-trivial first effort to use the new ExitCleanly(). Requires using the new CITEST_IMAGE (see prior commit) because nginx causes the tests to fail: [FAILED] Unexpected warnings seen on stderr: \ level=warning \ msg="HEALTHCHECK is not supported for OCI image format ... Oh, I also took the liberty of rewriting "play kube" -> "kube play". Signed-off-by: Ed Santiago --- test/e2e/play_build_test.go | 53 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/test/e2e/play_build_test.go b/test/e2e/play_build_test.go index 4398c5a3ad..b416d8275d 100644 --- a/test/e2e/play_build_test.go +++ b/test/e2e/play_build_test.go @@ -12,7 +12,6 @@ import ( . "github.com/containers/podman/v4/test/utils" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - . "github.com/onsi/gomega/gexec" ) var _ = Describe("Podman play kube with build", func() { @@ -51,12 +50,12 @@ status: {} ` var playBuildFile = ` -FROM quay.io/libpod/alpine_nginx:latest +FROM ` + CITEST_IMAGE + ` LABEL homer=dad COPY copyfile /copyfile ` var prebuiltImage = ` -FROM quay.io/libpod/alpine_nginx:latest +FROM ` + CITEST_IMAGE + ` LABEL marge=mom ` @@ -84,17 +83,17 @@ LABEL marge=mom Expect(os.Chdir(yamlDir)).To(Succeed()) defer func() { (Expect(os.Chdir(cwd)).To(BeNil())) }() - session := podmanTest.Podman([]string{"play", "kube", "top.yaml"}) + session := podmanTest.Podman([]string{"kube", "play", "top.yaml"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(ExitCleanly()) exists := podmanTest.Podman([]string{"image", "exists", "foobar"}) exists.WaitWithDefaultTimeout() - Expect(exists).Should(Exit(0)) + Expect(exists).Should(ExitCleanly()) inspect := podmanTest.Podman([]string{"container", "inspect", "top_pod-foobar"}) inspect.WaitWithDefaultTimeout() - Expect(inspect).Should(Exit(0)) + Expect(inspect).Should(ExitCleanly()) inspectData := inspect.InspectContainerToJSON() Expect(inspectData).ToNot(BeEmpty()) Expect(inspectData[0].Config.Labels).To(HaveKeyWithValue("homer", "dad")) @@ -121,17 +120,17 @@ LABEL marge=mom Expect(os.Chdir(yamlDir)).To(Succeed()) defer func() { (Expect(os.Chdir(cwd)).To(BeNil())) }() - session := podmanTest.Podman([]string{"play", "kube", "top.yaml"}) + session := podmanTest.Podman([]string{"kube", "play", "top.yaml"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(ExitCleanly()) exists := podmanTest.Podman([]string{"image", "exists", "foobar"}) exists.WaitWithDefaultTimeout() - Expect(exists).Should(Exit(0)) + Expect(exists).Should(ExitCleanly()) inspect := podmanTest.Podman([]string{"container", "inspect", "top_pod-foobar"}) inspect.WaitWithDefaultTimeout() - Expect(inspect).Should(Exit(0)) + Expect(inspect).Should(ExitCleanly()) inspectData := inspect.InspectContainerToJSON() Expect(inspectData).ToNot(BeEmpty()) Expect(inspectData[0].Config.Labels).To(HaveKeyWithValue("homer", "dad")) @@ -169,15 +168,15 @@ LABEL marge=mom // Build the image into the local store build := podmanTest.Podman([]string{"build", "-t", "foobar", "-f", "Containerfile"}) build.WaitWithDefaultTimeout() - Expect(build).Should(Exit(0)) + Expect(build).Should(ExitCleanly()) - session := podmanTest.Podman([]string{"play", "kube", "top.yaml"}) + session := podmanTest.Podman([]string{"kube", "play", "top.yaml"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(ExitCleanly()) inspect := podmanTest.Podman([]string{"container", "inspect", "top_pod-foobar"}) inspect.WaitWithDefaultTimeout() - Expect(inspect).Should(Exit(0)) + Expect(inspect).Should(ExitCleanly()) inspectData := inspect.InspectContainerToJSON() Expect(inspectData).ToNot(BeEmpty()) Expect(inspectData[0].Config.Labels).To(Not(HaveKey("homer"))) @@ -216,15 +215,15 @@ LABEL marge=mom // Build the image into the local store build := podmanTest.Podman([]string{"build", "-t", "foobar", "-f", "Containerfile"}) build.WaitWithDefaultTimeout() - Expect(build).Should(Exit(0)) + Expect(build).Should(ExitCleanly()) - session := podmanTest.Podman([]string{"play", "kube", "--build=false", "top.yaml"}) + session := podmanTest.Podman([]string{"kube", "play", "--build=false", "top.yaml"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(ExitCleanly()) inspect := podmanTest.Podman([]string{"container", "inspect", "top_pod-foobar"}) inspect.WaitWithDefaultTimeout() - Expect(inspect).Should(Exit(0)) + Expect(inspect).Should(ExitCleanly()) inspectData := inspect.InspectContainerToJSON() Expect(inspectData).ToNot(BeEmpty()) Expect(inspectData[0].Config.Labels).To(Not(HaveKey("homer"))) @@ -263,15 +262,15 @@ LABEL marge=mom // Build the image into the local store build := podmanTest.Podman([]string{"build", "-t", "foobar", "-f", "Containerfile"}) build.WaitWithDefaultTimeout() - Expect(build).Should(Exit(0)) + Expect(build).Should(ExitCleanly()) - session := podmanTest.Podman([]string{"play", "kube", "--build", "top.yaml"}) + session := podmanTest.Podman([]string{"kube", "play", "--build", "top.yaml"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(ExitCleanly()) inspect := podmanTest.Podman([]string{"container", "inspect", "top_pod-foobar"}) inspect.WaitWithDefaultTimeout() - Expect(inspect).Should(Exit(0)) + Expect(inspect).Should(ExitCleanly()) inspectData := inspect.InspectContainerToJSON() Expect(inspectData).ToNot(BeEmpty()) Expect(inspectData[0].Config.Labels).To(HaveKeyWithValue("homer", "dad")) @@ -352,21 +351,21 @@ echo GOT-HERE session := podmanTest.Podman([]string{"kube", "play", "echo.yaml"}) session.WaitWithDefaultTimeout() - Expect(session).Should(Exit(0)) + Expect(session).Should(ExitCleanly()) cid := "echo_pod-foobar" wait := podmanTest.Podman([]string{"wait", cid}) wait.WaitWithDefaultTimeout() - Expect(wait).To(Exit(0)) + Expect(wait).To(ExitCleanly()) logs := podmanTest.Podman([]string{"logs", cid}) logs.WaitWithDefaultTimeout() - Expect(logs).Should(Exit(0)) + Expect(logs).Should(ExitCleanly()) Expect(logs.OutputToString()).To(Equal("parenBAR braceBAR dollardollarparenGOT-HERE interpBARolate")) inspect := podmanTest.Podman([]string{"container", "inspect", cid}) inspect.WaitWithDefaultTimeout() - Expect(inspect).Should(Exit(0)) + Expect(inspect).Should(ExitCleanly()) inspectData := inspect.InspectContainerToJSON() Expect(inspectData).ToNot(BeEmpty())