diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/apiv2/01-basic.at | 15 | ||||
-rw-r--r-- | test/apiv2/40-pods.at | 26 | ||||
-rwxr-xr-x | test/apiv2/test-apiv2 | 2 | ||||
-rw-r--r-- | test/e2e/create_staticip_test.go | 16 | ||||
-rw-r--r-- | test/e2e/healthcheck_run_test.go | 20 | ||||
-rw-r--r-- | test/e2e/login_logout_test.go | 52 | ||||
-rw-r--r-- | test/e2e/network_test.go | 80 | ||||
-rw-r--r-- | test/e2e/pod_create_test.go | 165 | ||||
-rw-r--r-- | test/e2e/ps_test.go | 3 | ||||
-rw-r--r-- | test/e2e/run_memory_test.go | 6 | ||||
-rw-r--r-- | test/e2e/run_networking_test.go | 11 | ||||
-rw-r--r-- | test/e2e/run_staticip_test.go | 16 | ||||
-rw-r--r-- | test/e2e/run_test.go | 16 | ||||
-rw-r--r-- | test/e2e/run_volume_test.go | 20 | ||||
-rw-r--r-- | test/e2e/search_test.go | 22 | ||||
-rw-r--r-- | test/system/010-images.bats | 36 | ||||
-rw-r--r-- | test/system/130-kill.bats | 27 | ||||
-rw-r--r-- | test/system/150-login.bats | 339 | ||||
-rw-r--r-- | test/system/500-networking.bats | 63 |
19 files changed, 892 insertions, 43 deletions
diff --git a/test/apiv2/01-basic.at b/test/apiv2/01-basic.at index a54063260..b8a049cdf 100644 --- a/test/apiv2/01-basic.at +++ b/test/apiv2/01-basic.at @@ -47,4 +47,19 @@ t GET info 200 \ .DefaultRuntime=runc \ .MemTotal~[0-9]\\+ +# Timing: make sure server stays responsive +t0=$SECONDS +for i in $(seq 1 10); do + # FIXME: someday: refactor t(), separate out the 'curl' logic so we + # can call it directly. Then we won't get ten annoying 'ok' lines. + t GET info 200 +done +t1=$SECONDS +delta_t=$((t1 - t2)) +if [ $delta_t -le 5 ]; then + _show_ok 1 "Time for ten /info requests ($delta_t seconds) <= 5s" +else + _show_ok 0 "Time for ten /info requests" "<= 5 seconds" "$delta_t seconds" +fi + # vim: filetype=sh diff --git a/test/apiv2/40-pods.at b/test/apiv2/40-pods.at index 705de94d2..8b5651cff 100644 --- a/test/apiv2/40-pods.at +++ b/test/apiv2/40-pods.at @@ -3,18 +3,20 @@ # test pod-related endpoints # -# FIXME! Shouldn't /create give an actual pod ID? -expected_id='machine.slice' -if rootless; then - expected_id=/libpod_parent -fi - t GET libpod/pods/json 200 null -t POST libpod/pods/create name=foo 201 .id=$expected_id +t POST libpod/pods/create name=foo 201 .id~[0-9a-f]\\{64\\} +pod_id=$(jq -r .id <<<"$output") t GET libpod/pods/foo/exists 204 +t GET libpod/pods/$pod_id/exists 204 t GET libpod/pods/notfoo/exists 404 -t GET libpod/pods/foo/json 200 .Config.name=foo .Containers=null -t GET libpod/pods/json 200 .[0].Config.name=foo .[0].Containers=null +t GET libpod/pods/foo/json 200 \ + .Config.name=foo \ + .Config.id=$pod_id \ + .Containers=null +t GET libpod/pods/json 200 \ + .[0].Config.name=foo \ + .[0].Config.id=$pod_id \ + .[0].Containers=null # Cannot create a dup pod with the same name t POST libpod/pods/create name=foo 409 .cause="pod already exists" @@ -35,8 +37,10 @@ t POST libpod/pods/foo/restart '' 500 .cause="no such container" t POST libpod/pods/bar/restart '' 404 -#t POST libpod/pods/prune '' 200 # FIXME: unimplemented, returns 500 -#t POST libpod/pods/prune 'a=b' 400 # FIXME: unimplemented, returns 500 +# FIXME: I'm not sure what 'prune' is supposed to do; as of 20200224 it +# just returns 200 (ok) with empty result list. +#t POST libpod/pods/prune '' 200 # FIXME: 2020-02-24 returns 200 {} +#t POST libpod/pods/prune 'a=b' 400 # FIXME: 2020-02-24 returns 200 # Clean up; and try twice, making sure that the second time fails t DELETE libpod/pods/foo 204 diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index fffd7b085..bc2ed142c 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -253,7 +253,7 @@ function start_service() { die "Cannot start service on non-localhost ($HOST)" fi - $PODMAN_BIN --root $WORKDIR system service --timeout 15000 tcp:127.0.0.1:$PORT \ + $PODMAN_BIN --root $WORKDIR system service --timeout 15 tcp:127.0.0.1:$PORT \ &> $WORKDIR/server.log & service_pid=$! diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go index 72a0638f9..693795637 100644 --- a/test/e2e/create_staticip_test.go +++ b/test/e2e/create_staticip_test.go @@ -4,6 +4,7 @@ package integration import ( "os" + "time" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" @@ -86,8 +87,23 @@ var _ = Describe("Podman create with --ip flag", func() { result = podmanTest.Podman([]string{"start", "test1"}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) + + // race prevention: wait until IP address is assigned + for i := 0; i < 5; i++ { + result = podmanTest.Podman([]string{"inspect", "--format", "{{.NetworkSettings.IPAddress}}", "test1"}) + result.WaitWithDefaultTimeout() + Expect(result.ExitCode()).To(Equal(0)) + if result.OutputToString() != "" { + break + } + time.Sleep(1 * time.Second) + } + Expect(result.OutputToString()).To(Equal(ip)) + + // test1 container is running with the given IP. result = podmanTest.Podman([]string{"start", "test2"}) result.WaitWithDefaultTimeout() Expect(result).To(ExitWithError()) + Expect(result.ErrorToString()).To(ContainSubstring("requested IP address " + ip + " is not available")) }) }) diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go index 7633261e3..19a8658ac 100644 --- a/test/e2e/healthcheck_run_test.go +++ b/test/e2e/healthcheck_run_test.go @@ -41,6 +41,26 @@ var _ = Describe("Podman healthcheck run", func() { Expect(session).To(ExitWithError()) }) + It("podman disable healthcheck with --no-healthcheck on valid container", func() { + SkipIfRemote() + session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"}) + hc.WaitWithDefaultTimeout() + Expect(hc.ExitCode()).To(Equal(125)) + }) + + It("podman disable healthcheck with --health-cmd=none on valid container", func() { + SkipIfRemote() + session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "none", "--name", "hc", healthcheck}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"}) + hc.WaitWithDefaultTimeout() + Expect(hc.ExitCode()).To(Equal(125)) + }) + It("podman healthcheck on valid container", func() { Skip("Extremely consistent flake - re-enable on debugging") session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck}) diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index 78c9b52d9..42698d270 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -19,14 +19,15 @@ import ( var _ = Describe("Podman login and logout", func() { var ( - tempdir string - err error - podmanTest *PodmanTestIntegration - authPath string - certPath string - port int - server string - testImg string + tempdir string + err error + podmanTest *PodmanTestIntegration + authPath string + certPath string + port int + server string + testImg string + registriesConfWithSearch []byte ) BeforeEach(func() { @@ -64,6 +65,9 @@ var _ = Describe("Podman login and logout", func() { f.Sync() port = 4999 + config.GinkgoConfig.ParallelNode server = strings.Join([]string{"localhost", strconv.Itoa(port)}, ":") + + registriesConfWithSearch = []byte(fmt.Sprintf("[registries.search]\nregistries = ['%s']", server)) + testImg = strings.Join([]string{server, "test-apline"}, "/") os.MkdirAll(filepath.Join("/etc/containers/certs.d", server), os.ModePerm) @@ -113,6 +117,38 @@ var _ = Describe("Podman login and logout", func() { Expect(session).To(ExitWithError()) }) + It("podman login and logout without registry parameter", func() { + SkipIfRootless() + + registriesConf, err := ioutil.TempFile("", "TestLoginWithoutParameter") + Expect(err).To(BeNil()) + defer registriesConf.Close() + defer os.Remove(registriesConf.Name()) + + err = ioutil.WriteFile(registriesConf.Name(), []byte(registriesConfWithSearch), os.ModePerm) + Expect(err).To(BeNil()) + + // Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not + // run in parallel unless they opt in by calling t.Parallel(). So don’t do that. + oldRCP, hasRCP := os.LookupEnv("REGISTRIES_CONFIG_PATH") + defer func() { + if hasRCP { + os.Setenv("REGISTRIES_CONFIG_PATH", oldRCP) + } else { + os.Unsetenv("REGISTRIES_CONFIG_PATH") + } + }() + os.Setenv("REGISTRIES_CONFIG_PATH", registriesConf.Name()) + + session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To((Equal(0))) + + session = podmanTest.Podman([]string{"logout"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman login and logout with flag --authfile", func() { SkipIfRootless() authFile := filepath.Join(podmanTest.TempDir, "auth.json") diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index 9aed5351a..440d307b5 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -4,13 +4,15 @@ package integration import ( "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + . "github.com/containers/libpod/test/utils" "github.com/containers/storage/pkg/stringid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "io/ioutil" - "os" - "path/filepath" ) func writeConf(conf []byte, confPath string) { @@ -155,4 +157,76 @@ var _ = Describe("Podman network", func() { Expect(session.IsJSONOutputValid()).To(BeTrue()) }) + It("podman inspect container single CNI network", func() { + SkipIfRootless() + netName := "testNetSingleCNI" + network := podmanTest.Podman([]string{"network", "create", "--subnet", "10.50.50.0/24", netName}) + network.WaitWithDefaultTimeout() + Expect(network.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName) + + ctrName := "testCtr" + container := podmanTest.Podman([]string{"run", "-dt", "--network", netName, "--name", ctrName, ALPINE, "top"}) + container.WaitWithDefaultTimeout() + Expect(container.ExitCode()).To(BeZero()) + + inspect := podmanTest.Podman([]string{"inspect", ctrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(BeZero()) + conData := inspect.InspectContainerToJSON() + Expect(len(conData)).To(Equal(1)) + Expect(len(conData[0].NetworkSettings.Networks)).To(Equal(1)) + net, ok := conData[0].NetworkSettings.Networks[netName] + Expect(ok).To(BeTrue()) + Expect(net.NetworkID).To(Equal(netName)) + Expect(net.IPPrefixLen).To(Equal(24)) + Expect(strings.HasPrefix(net.IPAddress, "10.50.50.")).To(BeTrue()) + + // Necessary to ensure the CNI network is removed cleanly + rmAll := podmanTest.Podman([]string{"rm", "-f", ctrName}) + rmAll.WaitWithDefaultTimeout() + Expect(rmAll.ExitCode()).To(BeZero()) + }) + + It("podman inspect container two CNI networks", func() { + SkipIfRootless() + netName1 := "testNetTwoCNI1" + network1 := podmanTest.Podman([]string{"network", "create", "--subnet", "10.50.51.0/25", netName1}) + network1.WaitWithDefaultTimeout() + Expect(network1.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName1) + + netName2 := "testNetTwoCNI2" + network2 := podmanTest.Podman([]string{"network", "create", "--subnet", "10.50.51.128/26", netName2}) + network2.WaitWithDefaultTimeout() + Expect(network2.ExitCode()).To(BeZero()) + defer podmanTest.removeCNINetwork(netName2) + + ctrName := "testCtr" + container := podmanTest.Podman([]string{"run", "-dt", "--network", fmt.Sprintf("%s,%s", netName1, netName2), "--name", ctrName, ALPINE, "top"}) + container.WaitWithDefaultTimeout() + Expect(container.ExitCode()).To(BeZero()) + + inspect := podmanTest.Podman([]string{"inspect", ctrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect.ExitCode()).To(BeZero()) + conData := inspect.InspectContainerToJSON() + Expect(len(conData)).To(Equal(1)) + Expect(len(conData[0].NetworkSettings.Networks)).To(Equal(2)) + net1, ok := conData[0].NetworkSettings.Networks[netName1] + Expect(ok).To(BeTrue()) + Expect(net1.NetworkID).To(Equal(netName1)) + Expect(net1.IPPrefixLen).To(Equal(25)) + Expect(strings.HasPrefix(net1.IPAddress, "10.50.51.")).To(BeTrue()) + net2, ok := conData[0].NetworkSettings.Networks[netName2] + Expect(ok).To(BeTrue()) + Expect(net2.NetworkID).To(Equal(netName2)) + Expect(net2.IPPrefixLen).To(Equal(26)) + Expect(strings.HasPrefix(net2.IPAddress, "10.50.51.")).To(BeTrue()) + + // Necessary to ensure the CNI network is removed cleanly + rmAll := podmanTest.Podman([]string{"rm", "-f", ctrName}) + rmAll.WaitWithDefaultTimeout() + Expect(rmAll.ExitCode()).To(BeZero()) + }) }) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index 2efa36141..e0a10c202 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -1,7 +1,9 @@ package integration import ( + "fmt" "os" + "strings" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" @@ -117,4 +119,167 @@ var _ = Describe("Podman pod create", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) }) + + It("podman create pod with --no-hosts", func() { + SkipIfRemote() + name := "test" + podCreate := podmanTest.Podman([]string{"pod", "create", "--no-hosts", "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + alpineResolvConf := podmanTest.Podman([]string{"run", "-ti", "--rm", "--no-hosts", ALPINE, "cat", "/etc/hosts"}) + alpineResolvConf.WaitWithDefaultTimeout() + Expect(alpineResolvConf.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "cat", "/etc/hosts"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(podResolvConf.OutputToString()).To(Equal(alpineResolvConf.OutputToString())) + }) + + It("podman create pod with --no-hosts and no infra should fail", func() { + SkipIfRemote() + name := "test" + podCreate := podmanTest.Podman([]string{"pod", "create", "--no-hosts", "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) + + It("podman create pod with --add-host", func() { + SkipIfRemote() + name := "test" + podCreate := podmanTest.Podman([]string{"pod", "create", "--add-host", "test.example.com:12.34.56.78", "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "cat", "/etc/hosts"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(strings.Contains(podResolvConf.OutputToString(), "12.34.56.78 test.example.com")).To(BeTrue()) + }) + + It("podman create pod with --add-host and no infra should fail", func() { + SkipIfRemote() + name := "test" + podCreate := podmanTest.Podman([]string{"pod", "create", "--add-host", "test.example.com:12.34.56.78", "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) + + It("podman create pod with DNS server set", func() { + SkipIfRemote() + name := "test" + server := "12.34.56.78" + podCreate := podmanTest.Podman([]string{"pod", "create", "--dns", server, "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "cat", "/etc/resolv.conf"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(strings.Contains(podResolvConf.OutputToString(), fmt.Sprintf("nameserver %s", server))).To(BeTrue()) + }) + + It("podman create pod with DNS server set and no infra should fail", func() { + SkipIfRemote() + name := "test" + server := "12.34.56.78" + podCreate := podmanTest.Podman([]string{"pod", "create", "--dns", server, "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) + + It("podman create pod with DNS option set", func() { + SkipIfRemote() + name := "test" + option := "attempts:5" + podCreate := podmanTest.Podman([]string{"pod", "create", "--dns-opt", option, "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "cat", "/etc/resolv.conf"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(strings.Contains(podResolvConf.OutputToString(), fmt.Sprintf("options %s", option))).To(BeTrue()) + }) + + It("podman create pod with DNS option set and no infra should fail", func() { + SkipIfRemote() + name := "test" + option := "attempts:5" + podCreate := podmanTest.Podman([]string{"pod", "create", "--dns-opt", option, "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) + + It("podman create pod with DNS search domain set", func() { + SkipIfRemote() + name := "test" + search := "example.com" + podCreate := podmanTest.Podman([]string{"pod", "create", "--dns-search", search, "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "cat", "/etc/resolv.conf"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(strings.Contains(podResolvConf.OutputToString(), fmt.Sprintf("search %s", search))).To(BeTrue()) + }) + + It("podman create pod with DNS search domain set and no infra should fail", func() { + SkipIfRemote() + name := "test" + search := "example.com" + podCreate := podmanTest.Podman([]string{"pod", "create", "--dns-search", search, "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) + + It("podman create pod with IP address", func() { + SkipIfRemote() + SkipIfRootless() + name := "test" + ip := GetRandomIPAddress() + podCreate := podmanTest.Podman([]string{"pod", "create", "--ip", ip, "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "ip", "addr"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(strings.Contains(podResolvConf.OutputToString(), ip)).To(BeTrue()) + }) + + It("podman create pod with IP address and no infra should fail", func() { + SkipIfRemote() + name := "test" + ip := GetRandomIPAddress() + podCreate := podmanTest.Podman([]string{"pod", "create", "--ip", ip, "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) + + It("podman create pod with MAC address", func() { + SkipIfRemote() + SkipIfRootless() + name := "test" + mac := "92:d0:c6:0a:29:35" + podCreate := podmanTest.Podman([]string{"pod", "create", "--mac-address", mac, "--name", name}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(0)) + + podResolvConf := podmanTest.Podman([]string{"run", "--pod", name, "-ti", "--rm", ALPINE, "ip", "addr"}) + podResolvConf.WaitWithDefaultTimeout() + Expect(podResolvConf.ExitCode()).To(Equal(0)) + Expect(strings.Contains(podResolvConf.OutputToString(), mac)).To(BeTrue()) + }) + + It("podman create pod with MAC address and no infra should fail", func() { + SkipIfRemote() + name := "test" + mac := "92:d0:c6:0a:29:35" + podCreate := podmanTest.Podman([]string{"pod", "create", "--mac-address", mac, "--name", name, "--infra=false"}) + podCreate.WaitWithDefaultTimeout() + Expect(podCreate.ExitCode()).To(Equal(125)) + }) }) diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go index 48dd186e2..adbb9c16c 100644 --- a/test/e2e/ps_test.go +++ b/test/e2e/ps_test.go @@ -170,10 +170,11 @@ var _ = Describe("Podman ps", func() { _, ec, _ := podmanTest.RunLsContainer("test1") Expect(ec).To(Equal(0)) - result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.ID}} {{.Image}} {{.Labels}}"}) + result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.ID}} {{.Image}} {{.ImageID}} {{.Labels}}"}) result.WaitWithDefaultTimeout() Expect(strings.Contains(result.OutputToStringArray()[0], "table")).To(BeFalse()) Expect(strings.Contains(result.OutputToStringArray()[0], "ID")).To(BeTrue()) + Expect(strings.Contains(result.OutputToStringArray()[0], "ImageID")).To(BeTrue()) Expect(strings.Contains(result.OutputToStringArray()[1], "alpine:latest")).To(BeTrue()) Expect(result.ExitCode()).To(Equal(0)) }) diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go index a45735a8a..d60f2a8cd 100644 --- a/test/e2e/run_memory_test.go +++ b/test/e2e/run_memory_test.go @@ -70,7 +70,11 @@ var _ = Describe("Podman run memory", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(Equal("41943040")) + if cgroupsv2 { + Expect(session.OutputToString()).To(Equal("max")) + } else { + Expect(session.OutputToString()).To(Equal("41943040")) + } }) It("podman run memory-swappiness test", func() { diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 5e587b198..5be9db810 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -146,6 +146,17 @@ var _ = Describe("Podman run networking", func() { Expect(match).Should(BeTrue()) }) + It("podman run --net container: and --uts container:", func() { + ctrName := "ctrToJoin" + ctr1 := podmanTest.RunTopContainer(ctrName) + ctr1.WaitWithDefaultTimeout() + Expect(ctr1.ExitCode()).To(Equal(0)) + + ctr2 := podmanTest.Podman([]string{"run", "-d", "--net=container:" + ctrName, "--uts=container:" + ctrName, ALPINE, "true"}) + ctr2.WaitWithDefaultTimeout() + Expect(ctr2.ExitCode()).To(Equal(0)) + }) + It("podman run --net container: copies hosts and resolv", func() { SkipIfRootless() ctrName := "ctr1" diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go index 5b4842fea..5ad8f9fb0 100644 --- a/test/e2e/run_staticip_test.go +++ b/test/e2e/run_staticip_test.go @@ -3,7 +3,10 @@ package integration import ( + "fmt" + "net/http" "os" + "time" . "github.com/containers/libpod/test/utils" . "github.com/onsi/ginkgo" @@ -65,9 +68,20 @@ var _ = Describe("Podman run with --ip flag", func() { It("Podman run two containers with the same IP", func() { ip := GetRandomIPAddress() - result := podmanTest.Podman([]string{"run", "-d", "--ip", ip, ALPINE, "sleep", "999"}) + result := podmanTest.Podman([]string{"run", "-dt", "--ip", ip, nginx}) result.WaitWithDefaultTimeout() Expect(result.ExitCode()).To(Equal(0)) + for i := 0; i < 10; i++ { + fmt.Println("Waiting for nginx", err) + time.Sleep(1 * time.Second) + response, err := http.Get(fmt.Sprintf("http://%s", ip)) + if err != nil { + continue + } + if response.StatusCode == http.StatusOK { + break + } + } result = podmanTest.Podman([]string{"run", "-ti", "--ip", ip, ALPINE, "ip", "addr"}) result.WaitWithDefaultTimeout() Expect(result).To(ExitWithError()) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 3eb93b84a..9b6de6f65 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -374,7 +374,9 @@ var _ = Describe("Podman run", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(ContainSubstring("1048576")) + if !cgroupsv2 { // TODO: Test Simplification. For now, we only care about exit(0) w/ cgroupsv2 + Expect(session.OutputToString()).To(ContainSubstring("1048576")) + } }) It("podman run device-write-bps test", func() { @@ -392,7 +394,9 @@ var _ = Describe("Podman run", func() { } session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(ContainSubstring("1048576")) + if !cgroupsv2 { // TODO: Test Simplification. For now, we only care about exit(0) w/ cgroupsv2 + Expect(session.OutputToString()).To(ContainSubstring("1048576")) + } }) It("podman run device-read-iops test", func() { @@ -411,7 +415,9 @@ var _ = Describe("Podman run", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(ContainSubstring("100")) + if !cgroupsv2 { // TODO: Test Simplification. For now, we only care about exit(0) w/ cgroupsv2 + Expect(session.OutputToString()).To(ContainSubstring("100")) + } }) It("podman run device-write-iops test", func() { @@ -430,7 +436,9 @@ var _ = Describe("Podman run", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - Expect(session.OutputToString()).To(ContainSubstring("100")) + if !cgroupsv2 { // TODO: Test Simplification. For now, we only care about exit(0) w/ cgroupsv2 + Expect(session.OutputToString()).To(ContainSubstring("100")) + } }) It("podman run notify_socket", func() { diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 46c27dc2e..e31338dbc 100644 --- a/test/e2e/run_volume_test.go +++ b/test/e2e/run_volume_test.go @@ -15,6 +15,10 @@ import ( "github.com/onsi/gomega/gexec" ) +var VolumeTrailingSlashDockerfile = ` +FROM alpine:latest +VOLUME /test/` + var _ = Describe("Podman run with volumes", func() { var ( tempdir string @@ -421,4 +425,20 @@ var _ = Describe("Podman run with volumes", func() { Expect(len(outputArr)).To(Equal(1)) Expect(strings.Contains(outputArr[0], fileName)).To(BeTrue()) }) + + It("Podman mount over image volume with trailing /", func() { + image := "podman-volume-test:trailing" + podmanTest.BuildImage(VolumeTrailingSlashDockerfile, image, "false") + + ctrName := "testCtr" + create := podmanTest.Podman([]string{"create", "-v", "/tmp:/test", "--name", ctrName, image, "ls"}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + data := podmanTest.InspectContainer(ctrName) + Expect(len(data)).To(Equal(1)) + Expect(len(data[0].Mounts)).To(Equal(1)) + Expect(data[0].Mounts[0].Source).To(Equal("/tmp")) + Expect(data[0].Mounts[0].Destination).To(Equal("/test")) + }) }) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index d88231510..6d762d338 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -5,14 +5,13 @@ package integration import ( "bytes" "fmt" + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" "io/ioutil" "os" "strconv" "text/template" - - . "github.com/containers/libpod/test/utils" - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" ) type endpoint struct { @@ -164,13 +163,6 @@ registries = ['{{.Host}}:{{.Port}}']` } }) - It("podman search v2 registry with empty query", func() { - search := podmanTest.Podman([]string{"search", "registry.fedoraproject.org/"}) - search.WaitWithDefaultTimeout() - Expect(search.ExitCode()).To(Equal(0)) - Expect(len(search.OutputToStringArray())).To(BeNumerically(">=", 1)) - }) - It("podman search attempts HTTP if tls-verify flag is set false", func() { if podmanTest.Host.Arch == "ppc64le" { Skip("No registry image for ppc64le") @@ -225,6 +217,14 @@ registries = ['{{.Host}}:{{.Port}}']` Expect(search.ExitCode()).To(Equal(0)) Expect(search.OutputToString()).ShouldNot(BeEmpty()) + + // podman search v2 registry with empty query + searchEmpty := podmanTest.PodmanNoCache([]string{"search", fmt.Sprintf("%s/", registryEndpoints[3].Address()), "--tls-verify=false"}) + searchEmpty.WaitWithDefaultTimeout() + Expect(searchEmpty.ExitCode()).To(BeZero()) + Expect(len(searchEmpty.OutputToStringArray())).To(BeNumerically(">=", 1)) + match, _ := search.GrepString("my-alpine") + Expect(match).Should(BeTrue()) }) It("podman search attempts HTTP if registry is in registries.insecure and force secure is false", func() { diff --git a/test/system/010-images.bats b/test/system/010-images.bats index 66ef53590..3224c9b42 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -74,4 +74,40 @@ size | [0-9]\\\+ run_podman rm my-container } +@test "podman images - filter" { + skip_if_remote "podman commit -q is broken in podman-remote" + + run_podman inspect --format '{{.ID}}' $IMAGE + iid=$output + + run_podman images --noheading --filter=after=$iid + is "$output" "" "baseline: empty results from filter (after)" + + run_podman images --noheading --filter=before=$iid + is "$output" "" "baseline: empty results from filter (before)" + + # Create a dummy container, then commit that as an image. We will + # now be able to use before/after/since queries + run_podman run --name mytinycontainer $IMAGE true + run_podman commit -q mytinycontainer mynewimage + new_iid=$output + + # (refactor common options for legibility) + opts='--noheading --no-trunc --format={{.ID}}--{{.Repository}}:{{.Tag}}' + + run_podman images ${opts} --filter=after=$iid + is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: after" + + # Same thing, with 'since' instead of 'after' + run_podman images ${opts} --filter=since=$iid + is "$output" "sha256:$new_iid--localhost/mynewimage:latest" "filter: since" + + run_podman images ${opts} --filter=before=mynewimage + is "$output" "sha256:$iid--$IMAGE" "filter: before" + + # Clean up + run_podman rmi mynewimage + run_podman rm mytinycontainer +} + # vim: filetype=sh diff --git a/test/system/130-kill.bats b/test/system/130-kill.bats index 5e098d754..7c2b9bed8 100644 --- a/test/system/130-kill.bats +++ b/test/system/130-kill.bats @@ -6,10 +6,29 @@ load helpers @test "podman kill - test signal handling in containers" { + # podman-remote and crun interact poorly in f31: crun seems to gobble up + # some signals. + # Workaround: run 'env --default-signal sh' instead of just 'sh' in + # the container. Since env on our regular alpine image doesn't support + # that flag, we need to pull fedora-minimal. See: + # https://github.com/containers/libpod/issues/5004 + # FIXME: remove this kludge once we get rid of podman-remote + local _image=$IMAGE + local _sh_cmd="sh" + if is_remote; then + _image=quay.io/libpod/fedora-minimal:latest + _sh_cmd="env --default-signal sh" + fi + # Start a container that will handle all signals by emitting 'got: N' local -a signals=(1 2 3 4 5 6 8 10 12 13 14 15 16 20 21 22 23 24 25 26 64) - run_podman run -d $IMAGE sh -c "for i in ${signals[*]}; do trap \"echo got: \$i\" \$i; done; echo READY; while ! test -e /stop; do sleep 0.05; done;echo DONE" - cid="$output" + run_podman run -d $_image $_sh_cmd -c \ + "for i in ${signals[*]}; do trap \"echo got: \$i\" \$i; done; + echo READY; + while ! test -e /stop; do sleep 0.05; done; + echo DONE" + # Ignore output regarding pulling/processing container images + cid=$(echo "$output" | tail -1) # Run 'logs -f' on that container, but run it in the background with # redirection to a named pipe from which we (foreground job) read @@ -62,6 +81,10 @@ load helpers run_podman wait $cid run_podman rm $cid wait $podman_log_pid + + if [[ $_image != $IMAGE ]]; then + run_podman rmi $_image + fi } @test "podman kill - rejects invalid args" { diff --git a/test/system/150-login.bats b/test/system/150-login.bats new file mode 100644 index 000000000..e33217e14 --- /dev/null +++ b/test/system/150-login.bats @@ -0,0 +1,339 @@ +#!/usr/bin/env bats -*- bats -*- +# +# tests for podman login +# + +load helpers + +############################################################################### +# BEGIN one-time envariable setup + +# Create a scratch directory; our podman registry will run from here. We +# also use it for other temporary files like authfiles. +if [ -z "${PODMAN_LOGIN_WORKDIR}" ]; then + export PODMAN_LOGIN_WORKDIR=$(mktemp -d --tmpdir=${BATS_TMPDIR:-${TMPDIR:-/tmp}} podman_bats_login.XXXXXX) +fi + +# Randomly-generated username and password +if [ -z "${PODMAN_LOGIN_USER}" ]; then + export PODMAN_LOGIN_USER="user$(random_string 4)" + export PODMAN_LOGIN_PASS=$(random_string 15) +fi + +# Randomly-assigned port in the 5xxx range +if [ -z "${PODMAN_LOGIN_REGISTRY_PORT}" ]; then + for port in $(shuf -i 5000-5999);do + if ! { exec 3<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then + export PODMAN_LOGIN_REGISTRY_PORT=$port + break + fi + done +fi + +# Override any user-set path to an auth file +unset REGISTRY_AUTH_FILE + +# END one-time envariable setup +############################################################################### +# BEGIN filtering - none of these tests will work with podman-remote + +function setup() { + skip_if_remote "none of these tests work with podman-remote" + + basic_setup +} + +# END filtering - none of these tests will work with podman-remote +############################################################################### +# BEGIN first "test" - start a registry for use by other tests +# +# This isn't really a test: it's a helper that starts a local registry. +# Note that we're careful to use a root/runroot separate from our tests, +# so setup/teardown don't clobber our registry image. +# + +@test "podman login [start registry]" { + AUTHDIR=${PODMAN_LOGIN_WORKDIR}/auth + mkdir -p $AUTHDIR + + # Pull registry image, but into a separate container storage + mkdir -p ${PODMAN_LOGIN_WORKDIR}/root + mkdir -p ${PODMAN_LOGIN_WORKDIR}/runroot + PODMAN_LOGIN_ARGS="--root ${PODMAN_LOGIN_WORKDIR}/root --runroot ${PODMAN_LOGIN_WORKDIR}/runroot" + # Give it three tries, to compensate for flakes + run_podman ${PODMAN_LOGIN_ARGS} pull registry:2 || + run_podman ${PODMAN_LOGIN_ARGS} pull registry:2 || + run_podman ${PODMAN_LOGIN_ARGS} pull registry:2 + + # Registry image needs a cert. Self-signed is good enough. + CERT=$AUTHDIR/domain.crt + if [ ! -e $CERT ]; then + openssl req -newkey rsa:4096 -nodes -sha256 \ + -keyout $AUTHDIR/domain.key -x509 -days 2 \ + -out $AUTHDIR/domain.crt \ + -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=localhost" + fi + + # Store credentials where container will see them + if [ ! -e $AUTHDIR/htpasswd ]; then + run_podman ${PODMAN_LOGIN_ARGS} run --rm \ + --entrypoint htpasswd registry:2 \ + -Bbn ${PODMAN_LOGIN_USER} ${PODMAN_LOGIN_PASS} \ + > $AUTHDIR/htpasswd + + # In case $PODMAN_TEST_KEEP_LOGIN_REGISTRY is set, for testing later + echo "${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS}" \ + > $AUTHDIR/htpasswd-plaintext + fi + + # Run the registry container. + run_podman '?' ${PODMAN_LOGIN_ARGS} rm -f registry + run_podman ${PODMAN_LOGIN_ARGS} run -d \ + -p ${PODMAN_LOGIN_REGISTRY_PORT}:5000 \ + --name registry \ + -v $AUTHDIR:/auth:Z \ + -e "REGISTRY_AUTH=htpasswd" \ + -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ + -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ + -e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \ + -e REGISTRY_HTTP_TLS_KEY=/auth/domain.key \ + registry:2 +} + +# END first "test" - start a registry for use by other tests +############################################################################### +# BEGIN actual tests +# BEGIN primary podman login/push/pull tests + +@test "podman login - basic test" { + run_podman login --tls-verify=false \ + --username ${PODMAN_LOGIN_USER} \ + --password-stdin \ + localhost:${PODMAN_LOGIN_REGISTRY_PORT} <<<"${PODMAN_LOGIN_PASS}" + is "$output" "Login Succeeded!" "output from podman login" + + # Now log out + run_podman logout localhost:${PODMAN_LOGIN_REGISTRY_PORT} + is "$output" "Removed login credentials for localhost:${PODMAN_LOGIN_REGISTRY_PORT}" \ + "output from podman logout" +} + +@test "podman login - with wrong credentials" { + registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT} + + run_podman 125 login --tls-verify=false \ + --username ${PODMAN_LOGIN_USER} \ + --password-stdin \ + $registry <<< "x${PODMAN_LOGIN_PASS}" + is "$output" \ + "Error: error logging into \"$registry\": invalid username/password" \ + 'output from podman login' +} + +@test "podman login - check generated authfile" { + authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json + rm -f $authfile + + registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT} + + run_podman login --authfile=$authfile \ + --tls-verify=false \ + --username ${PODMAN_LOGIN_USER} \ + --password ${PODMAN_LOGIN_PASS} \ + $registry + + # Confirm that authfile now exists + test -e $authfile || \ + die "podman login did not create authfile $authfile" + + # Special bracket form needed because of colon in host:port + run jq -r ".[\"auths\"][\"$registry\"][\"auth\"]" <$authfile + is "$status" "0" "jq from $authfile" + + expect_userpass="${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS}" + actual_userpass=$(base64 -d <<<"$output") + is "$actual_userpass" "$expect_userpass" "credentials stored in $authfile" + + + # Now log out and make sure credentials are removed + run_podman logout --authfile=$authfile $registry + + run jq -r '.auths' <$authfile + is "$status" "0" "jq from $authfile" + is "$output" "{}" "credentials removed from $authfile" +} + +# Some push tests +@test "podman push fail" { + # Create an invalid authfile + authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json + rm -f $authfile + + wrong_auth=$(base64 <<<"baduser:wrongpassword") + cat >$authfile <<EOF +{ + "auths": { + "localhost:${PODMAN_LOGIN_REGISTRY_PORT}": { + "auth": "$wrong_auth" + } + } +} +EOF + + run_podman 125 push --authfile=$authfile \ + --tls-verify=false $IMAGE \ + localhost:${PODMAN_LOGIN_REGISTRY_PORT}/badpush:1 + is "$output" ".*: unauthorized: authentication required" \ + "auth error on push" +} + +@test "podman push ok" { + # ARGH! We can't push $IMAGE (alpine_labels) to this registry; error is: + # + # Writing manifest to image destination + # Error: Error copying image to the remote destination: Error writing manifest: Error uploading manifest latest to localhost:${PODMAN_LOGIN_REGISTRY_PORT}/okpush: received unexpected HTTP status: 500 Internal Server Error + # + # Root cause: something to do with v1/v2 s1/s2: + # + # https://github.com/containers/skopeo/issues/651 + # + run_podman pull busybox + + # Preserve its ID for later comparison against push/pulled image + run_podman inspect --format '{{.Id}}' busybox + id_busybox=$output + + destname=ok-$(random_string 10 | tr A-Z a-z)-ok + # Use command-line credentials + run_podman push --tls-verify=false \ + --creds ${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS} \ + busybox localhost:${PODMAN_LOGIN_REGISTRY_PORT}/$destname + + # Yay! Pull it back + run_podman pull --tls-verify=false \ + --creds ${PODMAN_LOGIN_USER}:${PODMAN_LOGIN_PASS} \ + localhost:${PODMAN_LOGIN_REGISTRY_PORT}/$destname + + # Compare to original busybox + run_podman inspect --format '{{.Id}}' $destname + is "$output" "$id_busybox" "Image ID of pulled image == busybox" + + run_podman rmi busybox $destname +} + +# END primary podman login/push/pull tests +############################################################################### +# BEGIN cooperation with skopeo + +# Skopeo helper - keep this separate, so we can test with different +# envariable settings +function _test_skopeo_credential_sharing() { + if ! type -p skopeo; then + skip "skopeo not available" + fi + + registry=localhost:${PODMAN_LOGIN_REGISTRY_PORT} + + run_podman login "$@" --tls-verify=false \ + --username ${PODMAN_LOGIN_USER} \ + --password ${PODMAN_LOGIN_PASS} \ + $registry + + destname=skopeo-ok-$(random_string 10 | tr A-Z a-z)-ok + echo "# skopeo copy ..." + run skopeo copy "$@" \ + --format=v2s2 \ + --dest-tls-verify=false \ + containers-storage:$IMAGE \ + docker://$registry/$destname + echo "$output" + is "$status" "0" "skopeo copy - exit status" + is "$output" ".*Copying blob .*" "output of skopeo copy" + is "$output" ".*Copying config .*" "output of skopeo copy" + is "$output" ".*Writing manifest .*" "output of skopeo copy" + + echo "# skopeo inspect ..." + run skopeo inspect "$@" --tls-verify=false docker://$registry/$destname + echo "$output" + is "$status" "0" "skopeo inspect - exit status" + + got_name=$(jq -r .Name <<<"$output") + is "$got_name" "$registry/$dest_name" "skopeo inspect -> Name" + + # Now try without a valid login; it should fail + run_podman logout "$@" $registry + echo "# skopeo inspect [with no credentials] ..." + run skopeo inspect "$@" --tls-verify=false docker://$registry/$destname + echo "$output" + is "$status" "1" "skopeo inspect - exit status" + is "$output" ".*: unauthorized: authentication required" \ + "auth error on skopeo inspect" +} + +@test "podman login - shares credentials with skopeo - default auth file" { + if is_rootless; then + if [ -z "${XDG_RUNTIME_DIR}" ]; then + skip "skopeo does not match podman when XDG_RUNTIME_DIR unset; #823" + fi + fi + _test_skopeo_credential_sharing +} + +@test "podman login - shares credentials with skopeo - via envariable" { + skip "skopeo does not yet support REGISTRY_AUTH_FILE; #822" + authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json + rm -f $authfile + + REGISTRY_AUTH_FILE=$authfile _test_skopeo_credential_sharing + rm -f $authfile +} + +@test "podman login - shares credentials with skopeo - via --authfile" { + # Also test that command-line --authfile overrides envariable + authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json + rm -f $authfile + + fake_authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json + rm -f $fake_authfile + + REGISTRY_AUTH_FILE=$authfile _test_skopeo_credential_sharing --authfile=$authfile + + if [ -e $fake_authfile ]; then + die "REGISTRY_AUTH_FILE overrode command-line --authfile!" + fi + rm -f $authfile +} + +# END cooperation with skopeo +# END actual tests +############################################################################### +# BEGIN teardown (remove the registry container) + +@test "podman login [stop registry, clean up]" { + # For manual debugging; user may request keeping the registry running + if [ -n "${PODMAN_TEST_KEEP_LOGIN_REGISTRY}" ]; then + skip "[leaving registry running by request]" + fi + + run_podman --root ${PODMAN_LOGIN_WORKDIR}/root \ + --runroot ${PODMAN_LOGIN_WORKDIR}/runroot \ + rm -f registry + run_podman --root ${PODMAN_LOGIN_WORKDIR}/root \ + --runroot ${PODMAN_LOGIN_WORKDIR}/runroot \ + rmi -a + + # By default, clean up + if [ -z "${PODMAN_TEST_KEEP_LOGIN_WORKDIR}" ]; then + rm -rf ${PODMAN_LOGIN_WORKDIR} + fi + + # Make sure socket is closed + if { exec 3<> /dev/tcp/127.0.0.1/${PODMAN_LOGIN_REGISTRY_PORT}; } &>/dev/null; then + die "Socket still seems open" + fi +} + +# END teardown (remove the registry container) +############################################################################### + +# vim: filetype=sh diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats new file mode 100644 index 000000000..cd836610b --- /dev/null +++ b/test/system/500-networking.bats @@ -0,0 +1,63 @@ +#!/usr/bin/env bats -*- bats -*- +# +# Test podman local networking +# + +load helpers + +# Copied from tsweeney's https://github.com/containers/libpod/issues/4827 +@test "podman networking: port on localhost" { + skip_if_remote + random_1=$(random_string 30) + random_2=$(random_string 30) + + HOST_PORT=8080 + SERVER=http://localhost:$HOST_PORT + + # Create a test file with random content + INDEX1=$PODMAN_TMPDIR/hello.txt + echo $random_1 > $INDEX1 + + # Bind-mount this file with a different name to a container running httpd + run_podman run -d --name myweb -p "$HOST_PORT:80" \ + -v $INDEX1:/var/www/index.txt \ + -w /var/www \ + busybox httpd -f -p 80 + cid=$output + + # In that container, create a second file, using exec and redirection + run_podman exec -i myweb sh -c "cat > index2.txt" <<<"$random_2" + # ...verify its contents as seen from container. + run_podman exec -i myweb cat /var/www/index2.txt + is "$output" "$random_2" "exec cat index2.txt" + + # Verify http contents: curl from localhost + run curl -s $SERVER/index.txt + is "$output" "$random_1" "curl localhost:/index.txt" + run curl -s $SERVER/index2.txt + is "$output" "$random_2" "curl localhost:/index2.txt" + + # Verify http contents: wget from a second container + run_podman run --rm --net=host busybox wget -qO - $SERVER/index.txt + is "$output" "$random_1" "podman wget /index.txt" + run_podman run --rm --net=host busybox wget -qO - $SERVER/index2.txt + is "$output" "$random_2" "podman wget /index2.txt" + + # Tests #4889 - two-argument form of "podman ports" was broken + run_podman port myweb + is "$output" "80/tcp -> 0.0.0.0:$HOST_PORT" "port <cid>" + run_podman port myweb 80 + is "$output" "0.0.0.0:$HOST_PORT" "port <cid> 80" + run_podman port myweb 80/tcp + is "$output" "0.0.0.0:$HOST_PORT" "port <cid> 80/tcp" + + run_podman 125 port myweb 99/tcp + is "$output" 'Error: failed to find published port "99/tcp"' + + # Clean up + run_podman stop -t 1 myweb + run_podman rm myweb + run_podman rmi busybox +} + +# vim: filetype=sh |