summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/apiv2/10-images.at14
-rw-r--r--test/apiv2/12-imagesMore.at67
-rw-r--r--test/apiv2/15-manifest.at24
-rw-r--r--test/apiv2/20-containers.at52
-rw-r--r--test/apiv2/27-containersEvents.at4
-rw-r--r--test/apiv2/35-networks.at4
-rw-r--r--test/apiv2/40-pods.at2
-rw-r--r--test/apiv2/60-auth.at4
-rw-r--r--test/apiv2/70-short-names.at23
-rw-r--r--test/apiv2/python/rest_api/fixtures/api_testcase.py4
-rw-r--r--test/apiv2/python/rest_api/test_v2_0_0_container.py47
-rwxr-xr-xtest/apiv2/test-apiv2139
-rwxr-xr-xtest/buildah-bud/apply-podman-deltas41
-rw-r--r--test/buildah-bud/buildah-tests.diff25
-rwxr-xr-xtest/buildah-bud/run-buildah-bud-tests6
-rw-r--r--test/compose/disable_healthcheck/docker-compose.yml10
-rw-r--r--test/compose/disable_healthcheck/tests.sh2
-rw-r--r--test/compose/update_network_mtu/docker-compose.yml26
-rw-r--r--test/compose/update_network_mtu/tests.sh10
-rw-r--r--test/e2e/benchmarks_test.go2
-rw-r--r--test/e2e/build/Containerfile.with-platform1
-rw-r--r--test/e2e/build_test.go30
-rw-r--r--test/e2e/checkpoint_test.go140
-rw-r--r--test/e2e/commit_test.go2
-rw-r--r--test/e2e/common_test.go54
-rw-r--r--test/e2e/config.go8
-rw-r--r--test/e2e/config_amd64.go24
-rw-r--r--test/e2e/config_ppc64le.go8
-rw-r--r--test/e2e/container_inspect_test.go2
-rw-r--r--test/e2e/create_staticip_test.go2
-rw-r--r--test/e2e/create_staticmac_test.go2
-rw-r--r--test/e2e/create_test.go6
-rw-r--r--test/e2e/events_test.go21
-rw-r--r--test/e2e/generate_systemd_test.go8
-rw-r--r--test/e2e/healthcheck_run_test.go10
-rw-r--r--test/e2e/image_scp_test.go32
-rw-r--r--test/e2e/inspect_test.go4
-rw-r--r--test/e2e/kill_test.go20
-rw-r--r--test/e2e/libpod_suite_test.go5
-rw-r--r--test/e2e/logs_test.go33
-rw-r--r--test/e2e/manifest_test.go68
-rw-r--r--test/e2e/network_connect_disconnect_test.go19
-rw-r--r--test/e2e/network_test.go36
-rw-r--r--test/e2e/pause_test.go6
-rw-r--r--test/e2e/play_kube_test.go28
-rw-r--r--test/e2e/pod_clone_test.go194
-rw-r--r--test/e2e/pod_create_test.go103
-rw-r--r--test/e2e/pod_infra_container_test.go29
-rw-r--r--test/e2e/pod_pause_test.go47
-rw-r--r--test/e2e/prune_test.go23
-rw-r--r--test/e2e/pull_test.go8
-rw-r--r--test/e2e/push_test.go10
-rw-r--r--test/e2e/rmi_test.go38
-rw-r--r--test/e2e/run_aardvark_test.go55
-rw-r--r--test/e2e/run_networking_test.go4
-rw-r--r--test/e2e/run_privileged_test.go24
-rw-r--r--test/e2e/run_staticip_test.go4
-rw-r--r--test/e2e/run_test.go54
-rw-r--r--test/e2e/run_volume_test.go110
-rw-r--r--test/e2e/save_test.go10
-rw-r--r--test/e2e/search_test.go15
-rw-r--r--test/e2e/stats_test.go11
-rw-r--r--test/e2e/system_connection_test.go24
-rw-r--r--test/e2e/system_df_test.go24
-rw-r--r--test/e2e/system_reset_test.go12
-rw-r--r--test/e2e/systemd_activate_test.go57
-rw-r--r--test/e2e/systemd_test.go2
-rw-r--r--test/e2e/tree_test.go2
-rw-r--r--test/e2e/untag_test.go12
-rw-r--r--test/e2e/volume_create_test.go32
-rw-r--r--test/e2e/volume_ls_test.go31
-rw-r--r--test/e2e/volume_plugin_test.go68
-rw-r--r--test/framework/framework.go2
-rw-r--r--test/system/010-images.bats5
-rw-r--r--test/system/015-help.bats60
-rw-r--r--test/system/030-run.bats44
-rw-r--r--test/system/050-stop.bats15
-rw-r--r--test/system/055-rm.bats10
-rw-r--r--test/system/060-mount.bats10
-rw-r--r--test/system/065-cp.bats104
-rw-r--r--test/system/070-build.bats9
-rw-r--r--test/system/120-load.bats26
-rw-r--r--test/system/130-kill.bats10
-rw-r--r--test/system/150-login.bats2
-rw-r--r--test/system/160-volumes.bats62
-rw-r--r--test/system/170-run-userns.bats39
-rw-r--r--test/system/200-pod.bats68
-rw-r--r--test/system/250-systemd.bats70
-rw-r--r--test/system/410-selinux.bats6
-rw-r--r--test/system/500-networking.bats29
-rw-r--r--test/system/520-checkpoint.bats30
-rw-r--r--test/system/600-completion.bats102
-rwxr-xr-xtest/system/build-testimage76
-rw-r--r--test/system/helpers.bash47
-rw-r--r--test/system/helpers.systemd.bash4
-rw-r--r--test/testvol/Containerfile9
-rw-r--r--test/testvol/create.go26
-rw-r--r--test/testvol/list.go32
-rw-r--r--test/testvol/main.go53
-rw-r--r--test/testvol/remove.go26
-rw-r--r--test/testvol/util.go29
-rw-r--r--test/tools/go.mod2
-rw-r--r--test/tools/go.sum11
-rw-r--r--test/tools/vendor/github.com/cpuguy83/go-md2man/v2/Makefile1
-rw-r--r--test/tools/vendor/github.com/cpuguy83/go-md2man/v2/go-md2man.1.md1
-rw-r--r--test/tools/vendor/github.com/hashicorp/go-version/.travis.yml8
-rw-r--r--test/tools/vendor/github.com/hashicorp/go-version/LICENSE1
-rw-r--r--test/tools/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md2
-rw-r--r--test/tools/vendor/github.com/sirupsen/logrus/CHANGELOG.md2
-rw-r--r--test/tools/vendor/github.com/sirupsen/logrus/README.md2
-rw-r--r--test/tools/vendor/github.com/sirupsen/logrus/appveyor.yml8
-rw-r--r--test/tools/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go1
-rw-r--r--test/tools/vendor/github.com/sirupsen/logrus/terminal_check_unix.go1
-rw-r--r--test/tools/vendor/github.com/vbatts/git-validation/README.md3
-rw-r--r--test/tools/vendor/golang.org/x/mod/module/module.go6
-rw-r--r--test/tools/vendor/golang.org/x/tools/cmd/goimports/doc.go25
-rw-r--r--test/tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go29
-rw-r--r--test/tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go7
-rw-r--r--test/tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go11
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go6
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/gocommand/invoke.go6
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go20
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/imports/imports.go27
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go39
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go61
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/typeparams/common.go21
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/typeparams/coretype.go122
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/typeparams/normalize.go12
-rw-r--r--test/tools/vendor/golang.org/x/tools/internal/typeparams/termlist.go9
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/LICENSE27
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/PATENTS22
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/README2
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/adaptor.go193
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/codereview.cfg1
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/doc.go22
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/errors.go33
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/fmt.go187
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/format.go34
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/frame.go56
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/go.mod3
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/internal/internal.go8
-rw-r--r--test/tools/vendor/golang.org/x/xerrors/wrap.go106
-rw-r--r--test/tools/vendor/modules.txt7
143 files changed, 2803 insertions, 1425 deletions
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index fd04e3f1b..f03b95786 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -53,7 +53,7 @@ t POST "images/create?fromImage=alpine" 200 .error~null .status~".*Download comp
t POST "images/create?fromImage=alpine&tag=latest" 200
# 10977 - handle platform parameter correctly
-t POST "images/create?fromImage=testimage:20210610&platform=linux/arm64" 200
+t POST "images/create?fromImage=quay.io/libpod/testimage:20210610&platform=linux/arm64" 200
t GET "images/testimage:20210610/json" 200 \
.Architecture=arm64
@@ -225,6 +225,18 @@ t POST "images/load" ${TMPD}/test.tar 200 \
t GET libpod/images/quay.io/libpod/alpine:latest/exists 204
t GET libpod/images/quay.io/libpod/busybox:latest/exists 204
+CONTAINERFILE_WITH_ERR_TAR="${TMPD}/containerfile.tar"
+cat > $TMPD/containerfile << EOF
+FROM quay.io/fedora/fedora
+RUN echo 'some error' >&2
+EOF
+tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_WITH_ERR_TAR} containerfile &> /dev/null
+t POST "build?q=1&dockerfile=containerfile" $CONTAINERFILE_WITH_ERR_TAR 200
+response_output=$(cat "$WORKDIR/curl.result.out")
+if [[ ${response_output} == *"some error"* ]];then
+ _show_ok 0 "compat quiet build" "~ $response_output" "found output from stderr in API"
+fi
+
cleanBuildTest
# vim: filetype=sh
diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at
index 67b4f1c79..fc18dd2d7 100644
--- a/test/apiv2/12-imagesMore.at
+++ b/test/apiv2/12-imagesMore.at
@@ -6,6 +6,8 @@
red='\e[31m'
nc='\e[0m'
+start_registry
+
podman pull -q $IMAGE
t GET libpod/images/json 200 \
@@ -20,48 +22,51 @@ t GET libpod/images/$IMAGE/tree 200 \
t POST "libpod/images/nonesuch/tag?repo=myrepo&tag=mytag" 404
# Tag the image
-t POST "libpod/images/$IMAGE/tag?repo=localhost:5000/myrepo&tag=mytag" 201
+t POST "libpod/images/$IMAGE/tag?repo=localhost:$REGISTRY_PORT/myrepo&tag=mytag" 201
t GET libpod/images/$IMAGE/json 200 \
- .RepoTags[1]=localhost:5000/myrepo:mytag
-
-# Run registry container
-# FIXME this fails if python tests have been run first...
-podman run -d --name registry -p 5000:5000 quay.io/libpod/registry:2.7 /entrypoint.sh /etc/docker/registry/config.yml
-wait_for_port localhost 5000
-
-# Push to local registry and check output
-while read -r LINE
-do
- if echo "${LINE}" | jq --exit-status 'select( .status != null) | select ( .status | contains("digest: sha256:"))' &>/dev/null; then
- GOT_DIGEST="1"
- fi
-done < <(curl -sL "http://$HOST:$PORT/images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" -XPOST)
-if [ -z "${GOT_DIGEST}" ] ; then
- echo -e "${red}not ok: did not found digest in output${nc}" 1>&2;
-fi
-
-# Push to local registry
-t POST "images/localhost:5000/myrepo/push?tlsVerify=false&tag=mytag" 200
+ .RepoTags[1]=localhost:$REGISTRY_PORT/myrepo:mytag
+
+# Push to local registry...
+t POST "images/localhost:$REGISTRY_PORT/myrepo/push?tlsVerify=false&tag=mytag" 200
+
+# ...and check output. We can't use our built-in checks because this output
+# is a sequence of JSON objects, i.e., individual ones, not in a JSON array.
+# The lines themselves are valid JSON, but taken together they are not.
+readarray lines <<<"$output"
+s0=$(jq -r .status <<<"${lines[0]}")
+is "$s0" "The push refers to repository [localhost:$REGISTRY_PORT/myrepo:mytag]" \
+ "Push to local registry: first status line"
+
+# FIXME: is there a way to test the actual digest?
+s1=$(jq -r .status <<<"${lines[1]}")
+like "$s1" "mytag: digest: sha256:[0-9a-f]\{64\} size: [0-9]\+" \
+ "Push to local registry: second status line"
# Untag the image
-t POST "libpod/images/$iid/untag?repo=localhost:5000/myrepo&tag=mytag" 201
+t POST "libpod/images/$iid/untag?repo=localhost:$REGISTRY_PORT/myrepo&tag=mytag" 201
# Try to push non-existing image
-t POST "images/localhost:5000/idonotexist/push?tlsVerify=false" 404
+t POST "images/localhost:$REGISTRY_PORT/idonotexist/push?tlsVerify=false" 404
t GET libpod/images/$IMAGE/json 200 \
.RepoTags[-1]=$IMAGE
-# Remove the registry container
-t DELETE libpod/containers/registry?force=true 200
-
-# Remove images
+# Remove image
t DELETE libpod/images/$IMAGE 200 \
.ExitCode=0
-t DELETE libpod/images/quay.io/libpod/registry:2.7 200 \
+
+podman pull -q $IMAGE
+
+# test podman image SCP
+# ssh needs to work so we can validate that the failure is past argument parsing
+podman system connection add --default test ssh://$USER@localhost/run/user/$UID/podman/podman.sock
+# should fail but need to check the output...
+# status 125 here means that the save/load fails due to
+# cirrus weirdness with exec.Command. All of the args have been parsed sucessfully.
+t POST "libpod/images/scp/$IMAGE?destination=QA::" 500 \
+ .cause="exit status 125"
+t DELETE libpod/images/$IMAGE 200 \
.ExitCode=0
-if [ -z "${GOT_DIGEST}" ] ; then
- exit 1;
-fi
+stop_registry
diff --git a/test/apiv2/15-manifest.at b/test/apiv2/15-manifest.at
index 0dd7026fa..970bed5a8 100644
--- a/test/apiv2/15-manifest.at
+++ b/test/apiv2/15-manifest.at
@@ -2,18 +2,40 @@
#
# Tests for manifest list endpoints
+start_registry
+
t POST /v3.4.0/libpod/manifests/create?name=abc 200 \
.Id~[0-9a-f]\\{64\\}
id_abc=$(jq -r '.Id' <<<"$output")
t POST /v4.0.0/libpod/manifests/xyz 201 \
.Id~[0-9a-f]\\{64\\}
-echo xyz $output
id_xyz=$(jq -r '.Id' <<<"$output")
t GET /v3.4.0/libpod/manifests/$id_abc/exists 204
t GET /v4.0.0/libpod/manifests/$id_xyz/exists 204
+id_abc_image=$($PODMAN_BIN --root $WORKDIR/server_root image build -q --format=docker -<<EOF
+FROM alpine
+RUN >file1
+EOF
+)
+
+id_xyz_image=$($PODMAN_BIN --root $WORKDIR/server_root image build -q --format=docker -<<EOF
+FROM alpine
+RUN >file2
+EOF
+)
+
+t POST /v3.4.0/libpod/manifests/$id_abc/add images="[\"containers-storage:$id_abc_image\"]" 200
+t PUT /v4.0.0/libpod/manifests/$id_xyz operation='update' images="[\"containers-storage:$id_xyz_image\"]" 200
+
+t POST "/v3.4.0/libpod/manifests/abc:latest/push?destination=localhost:$REGISTRY_PORT%2Fabc:latest&tlsVerify=false&all=true" 200
+t POST "/v4.0.0/libpod/manifests/xyz:latest/registry/localhost:$REGISTRY_PORT%2Fxyz:latest?tlsVerify=false&all=true" 200
+
# /v3.x cannot delete a manifest list
t DELETE /v4.0.0/libpod/manifests/$id_abc 200
t DELETE /v4.0.0/libpod/manifests/$id_xyz 200
+
+podman rmi -a
+stop_registry
diff --git a/test/apiv2/20-containers.at b/test/apiv2/20-containers.at
index 4d32a1031..6ef4ef917 100644
--- a/test/apiv2/20-containers.at
+++ b/test/apiv2/20-containers.at
@@ -16,7 +16,12 @@ podman pull $ENV_WORKDIR_IMG &>/dev/null
# Ensure clean slate
podman rm -a -f &>/dev/null
-t GET "libpod/containers/json (at start: clean slate)" 200 length=0
+t GET "libpod/containers/json (at start: clean slate)" 200 \
+ "[]" \
+ length=0
+# check content type: https://github.com/containers/podman/issues/14647
+response_headers=$(cat "$WORKDIR/curl.headers.out")
+like "$response_headers" ".*Content-Type: application/json.*" "header does not contain application/json"
# Regression test for #12904 (race condition in logging code)
mytext="hi-there-$(random_string 15)"
@@ -45,16 +50,16 @@ t GET libpod/containers/json?all=true 200 \
.[0].IsInfra=false
# Test compat API for Network Settings (.Network is N/A when rootless)
-network_expect=
+network_expect="Networks=null"
if root; then
- network_expect='.[0].NetworkSettings.Networks.podman.NetworkID=podman'
+ network_expect="Networks.podman.NetworkID=podman"
fi
t GET /containers/json?all=true 200 \
length=1 \
.[0].Id~[0-9a-f]\\{64\\} \
.[0].Image=$IMAGE \
.[0].Mounts~.*/tmp \
- $network_expect
+ .[0].NetworkSettings.$network_expect
# compat API imageid with sha256: prefix
t GET containers/json?limit=1 200 \
@@ -95,6 +100,17 @@ fi
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
+# Issue #14676: make sure the stats show the memory limit specified for the container
+if root; then
+ CTRNAME=ctr-with-limit
+ podman run --name $CTRNAME -d -m 512m -v /tmp:/tmp $IMAGE top
+
+ t GET libpod/containers/$CTRNAME/stats?stream=false 200 \
+ .memory_stats.limit=536870912
+
+ podman rm -f $CTRNAME
+fi
+
# Issue #6799: it should be possible to start a container, even w/o args.
t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
.Id~[0-9a-f]\\{64\\}
@@ -239,6 +255,7 @@ t GET containers/$cid/json 200 \
t POST containers/create Image=$IMAGE Entrypoint='["top"]' 201 \
.Id~[0-9a-f]\\{64\\}
cid_top=$(jq -r '.Id' <<<"$output")
+
t GET containers/${cid_top}/json 200 \
.Config.Entrypoint[0]="top" \
.Config.Cmd='[]' \
@@ -477,10 +494,35 @@ for endpoint in containers/create libpod/containers/create; do
t POST libpod/containers/$cid/init 204
- t GET libpod/containers/$cid/json 200
+ t GET libpod/containers/$cid/json 200 \
+ .HostsPath=""
t DELETE containers/$cid 204
done
stop_service
start_service
+
+# Our states are different from Docker's.
+# Regression test for #14700 (Docker compat returning unknown "initialized" for status.status) to ensure the stay compatible
+podman create --name status-test $IMAGE sh -c "sleep 3"
+t GET containers/status-test/json 200 .State.Status="created"
+
+podman init status-test
+t GET containers/status-test/json 200 .State.Status="created"
+
+podman start status-test
+t GET containers/status-test/json 200 .State.Status="running"
+
+podman pause status-test
+t GET containers/status-test/json 200 .State.Status="paused"
+
+podman unpause status-test
+t GET containers/status-test/json 200 .State.Status="running"
+
+podman stop status-test &
+sleep 1
+t GET containers/status-test/json 200 .State.Status="stopping"
+
+sleep 3
+t GET containers/status-test/json 200 .State.Status="exited"
diff --git a/test/apiv2/27-containersEvents.at b/test/apiv2/27-containersEvents.at
index a86f2e353..e0a66e0ac 100644
--- a/test/apiv2/27-containersEvents.at
+++ b/test/apiv2/27-containersEvents.at
@@ -18,6 +18,10 @@ t GET "libpod/events?stream=false&since=$START" 200 \
'select(.status | contains("died")).Action=died' \
'select(.status | contains("died")).Actor.Attributes.containerExitCode=1'
+t GET "libpod/events?stream=false&since=$START" 200 \
+ 'select(.status | contains("start")).Action=start' \
+ 'select(.status | contains("start")).HealthStatus='\
+
# compat api, uses status=die (#12643)
t GET "events?stream=false&since=$START" 200 \
'select(.status | contains("start")).Action=start' \
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index 4aad4563d..fcff26521 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -78,8 +78,8 @@ t GET networks?filters="{\"id\":[\"$network1_id\"]}" 200 \
.[0].Name=network1 \
.[0].Id=$network1_id
# invalid filter
-t GET networks?filters='{"dangling":["1"]}' 500 \
- .cause='invalid filter "dangling"'
+t GET networks?filters='{"dangling":["true","0"]}' 500 \
+ .cause="got more than one value for filter key \"dangling\""
# (#9293 with no networks the endpoint should return empty array instead of null)
t GET networks?filters='{"name":["doesnotexists"]}' 200 \
"[]"
diff --git a/test/apiv2/40-pods.at b/test/apiv2/40-pods.at
index 0a5201213..80724a8d9 100644
--- a/test/apiv2/40-pods.at
+++ b/test/apiv2/40-pods.at
@@ -134,4 +134,6 @@ t GET libpod/pods/json?filters='{"label":["testl' 400 \
t DELETE libpod/pods/foo 200
t DELETE "libpod/pods/foo (pod has already been deleted)" 404
+t_timeout 5 GET "libpod/pods/stats?stream=true&delay=1" 200
+
# vim: filetype=sh
diff --git a/test/apiv2/60-auth.at b/test/apiv2/60-auth.at
index 1e087d12b..465b0a96d 100644
--- a/test/apiv2/60-auth.at
+++ b/test/apiv2/60-auth.at
@@ -3,7 +3,7 @@
# registry-related tests
#
-start_registry
+start_registry htpasswd
# Test unreachable
t POST /v1.40/auth username=$REGISTRY_USERNAME password=WrOnGPassWord serveraddress=does.not.exist.io:1234/ \
@@ -26,3 +26,5 @@ t POST /v1.40/auth username=$REGISTRY_USERNAME password=$REGISTRY_PASSWORD serve
200 \
.Status="Login Succeeded" \
.IdentityToken=""
+
+stop_registry
diff --git a/test/apiv2/70-short-names.at b/test/apiv2/70-short-names.at
index a5087c115..bd7f8e7bd 100644
--- a/test/apiv2/70-short-names.at
+++ b/test/apiv2/70-short-names.at
@@ -6,11 +6,16 @@
# Pull the libpod/quay image which is used in all tests below.
t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .status~".*Download complete.*"
+# 14291 - let a short-name resolve to a *local* non Docker-Hub image.
+t POST containers/create Image=alpine 201 .Id~[0-9a-f]\\{64\\}
+cid=$(jq -r '.Id' <<<"$output")
+t GET containers/$cid/json 200 .Image="quay.io/libpod/alpine:latest"
+podman rm -f $cid
########## TAG
t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201
-t DELETE "images/foo" 200
+t DELETE "images/docker.io/library/foo" 200
########## BUILD
@@ -52,9 +57,6 @@ t DELETE "images/foo" 200
########## TAG
-# Looking up 'alpine' will fail as it gets normalized to docker.io.
-t POST "images/alpine/tag?repo=foo" 404 .cause="image not known"
-
# The libpod endpoint will resolve to it without issues.
t GET "libpod/images/alpine/exists" 204
@@ -67,22 +69,21 @@ t GET "libpod/images/docker.io/library/foo/exists" 204
########## REMOVE
-t DELETE "images/alpine" 404 .cause="image not known" # fails since docker.io/library/alpine does not exist
t DELETE "images/foo" 200 # removes the previously tagged image
########## GET
# Same procedure as above but with the /get endpoint.
-t GET "images/alpine/get" 404 .cause="image not known"
t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201
t GET "images/foo/get" 200 '[POSIX tar archive]'
t DELETE "images/foo" 200
+t GET "images/alpine/get" 200
########## HISTORY
-t GET "images/alpine/history" 404 .cause="image not known"
+t GET "images/alpine/history" 200
t GET "images/quay.io/libpod/alpine/history" 200
t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201
t GET "libpod/images/foo/history" 200
@@ -91,7 +92,7 @@ t DELETE "images/foo" 200
########## PUSH
-t POST "images/alpine/push?destination=localhost:9999/do/not:exist" 404 .cause="image not known"
+t POST "images/alpine/push?destination=localhost:9999/do:exist" 200
t POST "images/quay.io/libpod/alpine/push?destination=localhost:9999/do/not:exist" 200 # Error is in the response
t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201
t POST "images/foo/push?destination=localhost:9999/do/not:exist" 200 # Error is in the response
@@ -100,7 +101,7 @@ t DELETE "images/foo"
########## CREATE A CONTAINER
-t POST "containers/create" Image=alpine 404 .cause="image not known"
+t POST "containers/create" Image=alpine 201
t POST "containers/create" Image=quay.io/libpod/alpine:latest 201
cid=$(jq -r '.Id' <<<"$output")
t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201
@@ -113,7 +114,7 @@ t DELETE "containers/$cid"
t POST "containers/create" Image=quay.io/libpod/alpine:latest 201
cid=$(jq -r '.Id' <<<"$output")
-t GET "images/alpine/get" 404 .cause="image not known"
+t GET "images/alpine/get" 200
t POST "commit?container=$cid&repo=foo&tag=tag" 201
t GET "images/foo/get" 404 .cause="image not known"
t GET "images/foo:tag/get" 200
@@ -127,7 +128,7 @@ t DELETE "containers/$cid"
# disable the docker.io enforcement.
stop_service
-CONTAINERS_CONF=$(pwd)/test/apiv2/containers.conf start_service
+CONTAINERS_CONF=$TESTS_DIR/containers.conf start_service
t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .status~".*Download complete.*"
t POST "images/alpine/tag?repo=foo" 201
diff --git a/test/apiv2/python/rest_api/fixtures/api_testcase.py b/test/apiv2/python/rest_api/fixtures/api_testcase.py
index 155e93928..f47136555 100644
--- a/test/apiv2/python/rest_api/fixtures/api_testcase.py
+++ b/test/apiv2/python/rest_api/fixtures/api_testcase.py
@@ -64,6 +64,10 @@ class APITestCase(unittest.TestCase):
def uri(path):
return APITestCase.PODMAN_URL + "/v2.0.0/libpod" + path
+ @staticmethod
+ def compat_uri(path):
+ return APITestCase.PODMAN_URL + "/v3.0.0/" + path
+
def resolve_container(self, path):
"""Find 'first' container and return 'Id' formatted into given URI path."""
diff --git a/test/apiv2/python/rest_api/test_v2_0_0_container.py b/test/apiv2/python/rest_api/test_v2_0_0_container.py
index a44786c0d..a6cd93a1a 100644
--- a/test/apiv2/python/rest_api/test_v2_0_0_container.py
+++ b/test/apiv2/python/rest_api/test_v2_0_0_container.py
@@ -1,10 +1,12 @@
import multiprocessing
import queue
import random
+import subprocess
import threading
import unittest
import requests
+import os
import time
from dateutil.parser import parse
@@ -358,5 +360,50 @@ class ContainerTestCase(APITestCase):
self.assertEqual(1000, out["HostConfig"]["Memory"])
+
+def execute_process(cmd):
+ return subprocess.run(
+ cmd,
+ shell=True,
+ check=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ )
+
+def create_named_network_ns(network_ns_name):
+ execute_process(f"ip netns add {network_ns_name}")
+ execute_process(f"ip netns exec {network_ns_name} ip link add enp2s0 type veth peer name eth0")
+ execute_process(f"ip netns exec {network_ns_name} ip addr add 10.0.1.0/24 dev eth0")
+ execute_process(f"ip netns exec {network_ns_name} ip link set eth0 up")
+ execute_process(f"ip netns exec {network_ns_name} ip link add enp2s1 type veth peer name eth1")
+ execute_process(f"ip netns exec {network_ns_name} ip addr add 10.0.2.0/24 dev eth1")
+ execute_process(f"ip netns exec {network_ns_name} ip link set eth1 up")
+
+def delete_named_network_ns(network_ns_name):
+ execute_process(f"ip netns delete {network_ns_name}")
+
+class ContainerCompatibleAPITestCase(APITestCase):
+ def test_inspect_network(self):
+ if os.getuid() != 0:
+ self.skipTest("test needs to be executed as root!")
+ try:
+ network_ns_name = "test-compat-api"
+ create_named_network_ns(network_ns_name)
+ self.podman.run("rm", "--all", "--force", check=True)
+ self.podman.run("run", "--net", f"ns:/run/netns/{network_ns_name}", "-d", "alpine", "top", check=True)
+
+ r = requests.post(self.uri(self.resolve_container("/containers/{}/start")))
+ self.assertIn(r.status_code, (204, 304), r.text)
+
+ r = requests.get(self.compat_uri(self.resolve_container("/containers/{}/json")))
+ self.assertEqual(r.status_code, 200, r.text)
+ self.assertId(r.content)
+ out = r.json()
+
+ self.assertEqual("10.0.2.0", out["NetworkSettings"]["SecondaryIPAddresses"][0]["Addr"])
+ self.assertEqual(24, out["NetworkSettings"]["SecondaryIPAddresses"][0]["PrefixLen"])
+ finally:
+ delete_named_network_ns(network_ns_name)
+
if __name__ == "__main__":
unittest.main()
diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2
index c3545522e..0fd282854 100755
--- a/test/apiv2/test-apiv2
+++ b/test/apiv2/test-apiv2
@@ -23,6 +23,8 @@ REGISTRY_IMAGE="${PODMAN_TEST_IMAGE_REGISTRY}/${PODMAN_TEST_IMAGE_USER}/registry
###############################################################################
# BEGIN setup
+USER=$PODMAN_ROOTLESS_USER
+UID=$PODMAN_ROOTLESS_UID
TMPDIR=${TMPDIR:-/tmp}
WORKDIR=$(mktemp --tmpdir -d $ME.tmp.XXXXXX)
@@ -54,6 +56,9 @@ fi
# Path to podman binary
PODMAN_BIN=${PODMAN:-${CONTAINERS_HELPER_BINARY_DIR}/podman}
+# Timeout for streamed responses
+CURL_TIMEOUT=0
+
# Cleanup handlers
clean_up_server() {
if [ -n "$service_pid" ]; then
@@ -62,7 +67,7 @@ clean_up_server() {
podman rm -a
podman rmi -af
- stop_registry
+ stop_registry --cleanup
stop_service
fi
}
@@ -87,6 +92,7 @@ trap err_handler ERR
#########
function die() {
echo "$ME: $*" >&2
+ clean_up_server
exit 1
}
@@ -214,24 +220,45 @@ function jsonify() {
}
#######
+# t_timeout # Timeout wrapper for test helper
+#######
+function t_timeout() {
+ CURL_TIMEOUT=$1; shift
+ local min_runtime=$((CURL_TIMEOUT - 1))
+ start=`date +%s`
+ t $@
+ local end=`date +%s`
+ local runtime=$((end-start))
+ if ! [[ "$runtime" -ge "$min_runtime" ]]; then
+ die "Error: Streaming time should be greater or equal to '$min_runtime'"
+ fi
+}
+
+#######
# t # Main test helper
#######
function t() {
local method=$1; shift
local path=$1; shift
- local curl_args
+ local -a curl_args
local content_type="application/json"
local testname="$method $path"
- # POST requests may be followed by one or more key=value pairs.
+
+ if [[ $CURL_TIMEOUT != 0 ]]; then
+ local c_timeout=$CURL_TIMEOUT
+ curl_args+=("-m $CURL_TIMEOUT")
+ CURL_TIMEOUT=0 # 'consume' timeout
+ fi
+ # POST and PUT requests may be followed by one or more key=value pairs.
# Slurp the command line until we see a 3-digit status code.
- if [[ $method = "POST" ]]; then
+ if [[ $method = "POST" || $method == "PUT" ]]; then
local -a post_args
for arg; do
case "$arg" in
*=*) post_args+=("$arg");
shift;;
- *.tar) curl_args="--data-binary @$arg" ;
+ *.tar) curl_args+=(--data-binary @$arg);
content_type="application/x-tar";
shift;;
application/*) content_type="$arg";
@@ -241,8 +268,8 @@ function t() {
esac
done
if [[ -z "$curl_args" ]]; then
- curl_args="-d $(jsonify ${post_args[@]})"
- testname="$testname [$curl_args]"
+ curl_args=(-d $(jsonify ${post_args[@]}))
+ testname="$testname [${curl_args[@]}]"
fi
fi
@@ -269,7 +296,7 @@ function t() {
# curl -X HEAD but without --head seems to wait for output anyway
if [[ $method == "HEAD" ]]; then
- curl_args="--head"
+ curl_args+=("--head")
fi
local expected_code=$1; shift
@@ -281,16 +308,15 @@ function t() {
# -s = silent, but --write-out 'format' gives us important response data
# The hairy "{ ...;rc=$?; } || :" lets us capture curl's exit code and
# give a helpful diagnostic if it fails.
- { response=$(curl -s -X $method ${curl_args} \
+ { response=$(curl -s -X $method "${curl_args[@]}" \
-H "Content-type: $content_type" \
--dump-header $WORKDIR/curl.headers.out \
--write-out '%{http_code}^%{content_type}^%{time_total}' \
-o $WORKDIR/curl.result.out "$url"); rc=$?; } || :
# Any error from curl is instant bad news, from which we can't recover
- if [[ $rc -ne 0 ]]; then
- echo "FATAL: curl failure ($rc) on $url - cannot continue" >&2
- exit 1
+ if [[ $rc -ne 0 ]] && [[ $c_timeout -eq 0 ]]; then
+ die "curl failure ($rc) on $url - cannot continue"
fi
# Show returned headers (without trailing ^M or empty lines) in log file.
@@ -380,11 +406,17 @@ function start_service() {
die "Cannot start service on non-localhost ($HOST)"
fi
- echo "rootdir: "$WORKDIR
- # Some tests use shortnames; force registry override to work around
- # docker.io throttling.
-# FIXME esm revisit pulling expected images re: shortnames caused tests to fail
-# env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf
+ # FIXME: EXPERIMENTAL: 2022-06-13: podman rootless needs a namespace. If
+ # system-service is the first podman command run (as is the case in CI)
+ # this will happen as a fork-exec, where the parent podman creates the
+ # namespace and the child is the server. Then, when stop_service() kills
+ # the parent, the child (server) happily stays alive and ruins subsequent
+ # tests that try to restart service with different settings.
+ # Workaround: run an unshare to get namespaces initialized.
+ if [[ $(id -u) != 0 ]]; then
+ $PODMAN_BIN unshare true
+ fi
+
$PODMAN_BIN \
--root $WORKDIR/server_root --syslog=true \
system service \
@@ -392,6 +424,7 @@ function start_service() {
tcp:127.0.0.1:$PORT \
&> $WORKDIR/server.log &
service_pid=$!
+ echo "# started service, pid $service_pid"
wait_for_port $HOST $PORT
}
@@ -401,7 +434,14 @@ function stop_service() {
if [[ -n $service_pid ]]; then
kill $service_pid || :
wait $service_pid || :
+ echo "# stopped service, pid $service_pid"
fi
+ service_pid=
+
+ if { exec 3<> /dev/tcp/$HOST/$PORT; } &>/dev/null; then
+ echo "# WARNING: stop_service: Service still running on port $PORT"
+ fi
+
}
####################
@@ -411,15 +451,17 @@ REGISTRY_PORT=
REGISTRY_USERNAME=
REGISTRY_PASSWORD=
function start_registry() {
- # We can be invoked multiple times, e.g. from different subtests, but
- # let's assume that once started we only kill it at the end of tests.
+ # We can be called multiple times, but each time should start a new
+ # registry container with (possibly) different configuration. That
+ # means that all callers must be responsible for invoking stop_registry.
if [[ -n "$REGISTRY_PORT" ]]; then
- return
+ die "start_registry invoked twice in succession, without stop_registry"
fi
+ # First arg is auth type (default: "none", but can also be "htpasswd")
+ local auth="${1:-none}"
+
REGISTRY_PORT=$(random_port)
- REGISTRY_USERNAME=u$(random_string 7)
- REGISTRY_PASSWORD=p$(random_string 7)
local REGDIR=$WORKDIR/registry
local AUTHDIR=$REGDIR/auth
@@ -433,42 +475,65 @@ function start_registry() {
podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE ||
podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE
- # Create a local cert and credentials
- # FIXME: is there a hidden "--quiet" flag? This is too noisy.
- 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=registry host certificate" \
- -addext subjectAltName=DNS:localhost
- htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \
- > $AUTHDIR/htpasswd
+ # Create a local cert (no need to do this more than once)
+ if [[ ! -e $AUTHDIR/domain.key ]]; then
+ # FIXME: is there a hidden "--quiet" flag? This is too noisy.
+ 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=registry host certificate" \
+ -addext subjectAltName=DNS:localhost
+ fi
+
+ # If invoked with auth=htpasswd, create credentials
+ REGISTRY_USERNAME=
+ REGISTRY_PASSWORD=
+ declare -a registry_auth_params=(-e "REGISTRY_AUTH=$auth")
+ if [[ "$auth" = "htpasswd" ]]; then
+ REGISTRY_USERNAME=u$(random_string 7)
+ REGISTRY_PASSWORD=p$(random_string 7)
+
+ htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \
+ > $AUTHDIR/htpasswd
+
+ registry_auth_params+=(
+ -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"
+ -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd"
+ )
+ fi
# Run the registry, and wait for it to come up
podman ${PODMAN_REGISTRY_ARGS} run -d \
-p ${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 \
+ "${registry_auth_params[@]}" \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/auth/domain.key \
${REGISTRY_IMAGE}
wait_for_port localhost $REGISTRY_PORT 10
+ echo "# started registry (auth=$auth) on port $PORT"
}
function stop_registry() {
local REGDIR=${WORKDIR}/registry
if [[ -d $REGDIR ]]; then
local OPTS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot"
- podman $OPTS stop -f -t 0 -a
+ podman $OPTS stop -i -t 0 registry
# rm/rmi are important when running rootless: without them we
# get EPERMS in tmpdir cleanup because files are owned by subuids.
- podman $OPTS rm -f -a
- podman $OPTS rmi -f -a
+ podman $OPTS rm -f -i registry
+ if [[ "$1" = "--cleanup" ]]; then
+ podman $OPTS rmi -f -a
+ fi
+ echo "# stopped registry on port $PORT"
fi
+
+ REGISTRY_PORT=
+ REGISTRY_USERNAME=
+ REGISTRY_PASSWORD=
}
#################
diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas
index 1ca171c4a..0b691dd0e 100755
--- a/test/buildah-bud/apply-podman-deltas
+++ b/test/buildah-bud/apply-podman-deltas
@@ -61,7 +61,12 @@ function _skip() {
local skip=$1; shift
local reason=$1; shift
- # All further arguments are test names
+ # All further arguments are test names. Make sure we're invoked with some!
+ if [[ -z "$*" ]]; then
+ echo "$ME: FATAL: Invalid use of '${FUNCNAME[1]}' at line ${BASH_LINENO[1]}: missing test-name argument(s)." >&2
+ exit 1
+ fi
+
for t in "$@"; do
if fgrep -qx "@test \"$t\" {" $BUD; then
$ECHO "@test \"$t\" : $skip \"$reason\""
@@ -150,13 +155,7 @@ errmsg "checking authfile: stat /tmp/nonexistent: no such file or directory" \
###############################################################################
# BEGIN tests that don't make sense under podman due to fundamental differences
-# TODO
-# Normally, when buildah exits 1 on error, podman exits 125.
-# These tests are the exception. They exit 1 under podman.
-skip "these tests exit 1 under podman, not 125" \
- "bud with --add-host" \
- "bud - invalid runtime flags test"
-
+# Fails with "Error: no context directory and no Containerfile specified"
skip "does not work under podman" \
"bud without any arguments should succeed"
@@ -167,8 +166,9 @@ skip "does not work under podman" \
skip "FIXME FIXME FIXME: argument-order incompatible with podman" \
"bud-squash-hardlinks"
-skip "FIXME FIXME FIXME: this passes on Ed's laptop, fails in CI??" \
- "bud-multi-stage-nocache-nocommit"
+# Fails with "Error: context must be a directory: /path/to/Dockerfile"
+skip "podman-build fails with 'context must be a directory'" \
+ "bud with specified context should succeed if context contains existing Dockerfile"
###############################################################################
# BEGIN tests which are skipped because they make no sense under podman-remote
@@ -193,6 +193,13 @@ skip_if_remote "volumes don't work with podman-remote" \
"buildah bud --volume" \
"buildah-bud-policy"
+skip_if_remote "--build-context option not implemented in podman-remote" \
+ "build-with-additional-build-context and COPY, additional context from host" \
+ "build-with-additional-build-context and RUN --mount=from=, additional-context not image and also test conflict with stagename" \
+
+skip_if_remote "env-variable for Containerfile.in pre-processing is not propogated on remote" \
+ "bud with Containerfile.in, via envariable" \
+
# Requires a local file outside context dir
skip_if_remote "local keyfile not sent to podman-remote" \
"bud with encrypted FROM image"
@@ -210,6 +217,12 @@ skip_if_remote "--output option not implemented in podman-remote" \
"build with custom build output and output rootfs to tar by pipe" \
"build with custom build output must fail for bad input"
+# https://github.com/containers/podman/issues/14544
+skip_if_remote "logfile not implemented on remote" "bud-logfile-with-split-logfile-by-platform"
+
+skip_if_remote "envariables do not automatically work with -remote." \
+ "build proxy"
+
###############################################################################
# BEGIN tests which are skipped due to actual podman or podman-remote bugs.
@@ -222,10 +235,12 @@ skip_if_remote "FIXME FIXME FIXME: find a way to clean up their podman calls" \
"bud with run should not leave mounts behind cleanup test" \
"bud with custom files in /run/ should persist cleanup test"
-skip_if_remote "Do envariables work with -remote? Please look into this." \
- "build proxy"
+# Under podman-remote, the "Ignoring <stdin>:5:2: error: #error" message
+# is never seen. (Not even as stdout/stderr on the server; Ed checked).
+skip_if_remote "FIXME FIXME FIXME: 'Ignoring' warning is never seen" \
+ "bud with preprocessor error"
+# END tests which are skipped due to actual podman or podman-remote bugs.
###############################################################################
-# Done.
exit $RC
diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff
index 6fa36d904..399042240 100644
--- a/test/buildah-bud/buildah-tests.diff
+++ b/test/buildah-bud/buildah-tests.diff
@@ -1,15 +1,15 @@
-From 8a8fa1a75e0fa3261263afbc8c2504feb430df6a Mon Sep 17 00:00:00 2001
+From 6508e3df2a129554fdf8336d8a6f0cdcc6fd4832 Mon Sep 17 00:00:00 2001
From: Ed Santiago <santiago@redhat.com>
Date: Tue, 9 Feb 2021 17:28:05 -0700
Subject: [PATCH] tweaks for running buildah tests under podman
Signed-off-by: Ed Santiago <santiago@redhat.com>
---
- tests/helpers.bash | 69 ++++++++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 66 insertions(+), 3 deletions(-)
+ tests/helpers.bash | 70 ++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 67 insertions(+), 3 deletions(-)
diff --git a/tests/helpers.bash b/tests/helpers.bash
-index e3087063..b3a8f5ee 100644
+index e3087063..178a486e 100644
--- a/tests/helpers.bash
+++ b/tests/helpers.bash
@@ -51,6 +51,23 @@ EOF
@@ -60,13 +60,13 @@ index e3087063..b3a8f5ee 100644
# There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount`
# do not work in rootless session since a normal user cannot mount a filesystem unless they're in a user namespace along with its
# own mount namespace. In order to run such specific commands from a rootless session we must perform `buildah unshare`.
-@@ -247,8 +274,35 @@ function run_buildah() {
+@@ -247,8 +274,36 @@ function run_buildah() {
--retry) retry=3; shift;; # retry network flakes
esac
+ local podman_or_buildah=${BUILDAH_BINARY}
+ local _opts="${ROOTDIR_OPTS} ${BUILDAH_REGISTRY_OPTS}"
-+ if [[ $1 == "build" || $1 == "build-using-dockerfile" ]]; then
++ if [[ $1 == "build" || $1 == "build-using-dockerfile" || $1 == "bud" ]]; then
+ shift
+ # podman defaults to --layers=true; buildah to --false.
+ # If command line includes explicit --layers, leave it untouched,
@@ -82,10 +82,11 @@ index e3087063..b3a8f5ee 100644
+ _opts=
+ fi
+
-+ # podman always exits 125 where buildah exits 1 or 2 (or, in the
-+ # case of git, 128, which is a bug in git, but I won't harp on that).
++ # Special case: there's one test that invokes git in such
++ # a way that it exits 128 (which IMO is a bug in git).
++ # podman exits 125 in that case.
+ case $expected_rc in
-+ 1|2|128) expected_rc=125 ;;
++ 128) expected_rc=125 ;;
+ esac
+ fi
+ local cmd_basename=$(basename ${podman_or_buildah})
@@ -97,7 +98,7 @@ index e3087063..b3a8f5ee 100644
# If session is rootless and `buildah mount` is invoked, perform unshare,
# since normal user cannot mount a filesystem unless they're in a user namespace along with its own mount namespace.
-@@ -262,8 +316,8 @@ function run_buildah() {
+@@ -262,8 +317,8 @@ function run_buildah() {
retry=$(( retry - 1 ))
# stdout is only emitted upon error; this echo is to help a debugger
@@ -108,7 +109,7 @@ index e3087063..b3a8f5ee 100644
# without "quotes", multiple lines are glommed together into one
if [ -n "$output" ]; then
echo "$output"
-@@ -595,6 +649,15 @@ function skip_if_no_docker() {
+@@ -595,6 +650,15 @@ function skip_if_no_docker() {
fi
}
@@ -125,5 +126,5 @@ index e3087063..b3a8f5ee 100644
daemondir=${TEST_SCRATCH_DIR}/git-daemon
mkdir -p ${daemondir}/repo
--
-2.35.1
+2.35.3
diff --git a/test/buildah-bud/run-buildah-bud-tests b/test/buildah-bud/run-buildah-bud-tests
index eb8de5618..4ff062496 100755
--- a/test/buildah-bud/run-buildah-bud-tests
+++ b/test/buildah-bud/run-buildah-bud-tests
@@ -93,6 +93,12 @@ fi
# From here on out, any error is fatal
set -e
+# Run sudo early, to refresh the credentials cache. This is a NOP under CI,
+# but might be appreciated by developers who run this script, step away
+# during the git-checkout-buildah step, then come back twenty minutes later
+# to an expired sudo prompt and no tests have run.
+sudo --validate
+
# Before pulling buildah (while still cd'ed to podman repo), try to determine
# if this is a PR, and if so if it's a revendoring of buildah. We use this to
# try to offer a helpful hint on failure.
diff --git a/test/compose/disable_healthcheck/docker-compose.yml b/test/compose/disable_healthcheck/docker-compose.yml
new file mode 100644
index 000000000..1f608c895
--- /dev/null
+++ b/test/compose/disable_healthcheck/docker-compose.yml
@@ -0,0 +1,10 @@
+version: "3.7"
+services:
+ noHc:
+ image: alpine
+ container_name: noHc
+ ports:
+ - "4000:80"
+ restart: unless-stopped
+ healthcheck:
+ disable: true
diff --git a/test/compose/disable_healthcheck/tests.sh b/test/compose/disable_healthcheck/tests.sh
new file mode 100644
index 000000000..2460a687e
--- /dev/null
+++ b/test/compose/disable_healthcheck/tests.sh
@@ -0,0 +1,2 @@
+podman inspect --format='{{.Config.Healthcheck.Test}}' noHc
+like $output "[NONE]" "$testname: healthcheck properly disabled"
diff --git a/test/compose/update_network_mtu/docker-compose.yml b/test/compose/update_network_mtu/docker-compose.yml
new file mode 100644
index 000000000..fabd7b4f2
--- /dev/null
+++ b/test/compose/update_network_mtu/docker-compose.yml
@@ -0,0 +1,26 @@
+version: '3.7'
+
+services:
+ nginx:
+ image: alpine
+ ports:
+ - 8000:5000
+ networks:
+ - default
+ - macvlan_net
+
+networks:
+ default:
+ driver: bridge
+ driver_opts:
+ com.docker.network.bridge.name: docker0
+ com.docker.network.driver.mtu: 9000
+ macvlan_net:
+ driver: macvlan
+ driver_opts:
+ mode: bridge
+ ipam:
+ config:
+ -
+ subnet: 192.168.20.0/24
+ gateway: 192.168.20.1
diff --git a/test/compose/update_network_mtu/tests.sh b/test/compose/update_network_mtu/tests.sh
new file mode 100644
index 000000000..57411eb34
--- /dev/null
+++ b/test/compose/update_network_mtu/tests.sh
@@ -0,0 +1,10 @@
+# -*- bash -*-
+
+podman network inspect --format='{{ range . }} {{ .Options.mtu }} {{ end }}' update_network_mtu_default
+like "$output" "9000" "$testname : network mtu is set"
+
+podman network inspect --format='{{ range . }} {{ .NetworkInterface }} {{ end }}' update_network_mtu_default
+like "$output" "docker0" "$testname: network interface is set"
+
+podman network inspect --format='{{ range . }} {{ .Options.mode }} {{ end }}' update_network_mtu_macvlan_net
+like "$output" "bridge" "$testname : network mode is set"
diff --git a/test/e2e/benchmarks_test.go b/test/e2e/benchmarks_test.go
index ef4d51893..fe045b97a 100644
--- a/test/e2e/benchmarks_test.go
+++ b/test/e2e/benchmarks_test.go
@@ -132,7 +132,7 @@ var _ = Describe("Podman Benchmark Suite", func() {
Measure("Podman Benchmark Suite", func(b Benchmarker) {
registryOptions := &podmanRegistry.Options{
- Image: "docker-archive:" + imageTarPath(registry),
+ Image: "docker-archive:" + imageTarPath(REGISTRY_IMAGE),
}
for i := range allBenchmarks {
diff --git a/test/e2e/build/Containerfile.with-platform b/test/e2e/build/Containerfile.with-platform
new file mode 100644
index 000000000..3bb585a0a
--- /dev/null
+++ b/test/e2e/build/Containerfile.with-platform
@@ -0,0 +1 @@
+FROM --platform=$TARGETPLATFORM alpine
diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go
index dcdd17143..9ecc2f8c6 100644
--- a/test/e2e/build_test.go
+++ b/test/e2e/build_test.go
@@ -85,7 +85,7 @@ var _ = Describe("Podman build", func() {
})
It("podman build with a secret from file and verify if secret file is not leaked into image", func() {
- session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/"})
+ session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/secret-verify-leak"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(ContainSubstring("somesecret"))
@@ -178,6 +178,32 @@ var _ = Describe("Podman build", func() {
Expect(session).Should(Exit(0))
})
+ It("podman build verify explicit cache use with squash-all and --layers", func() {
+ session := podmanTest.Podman([]string{"build", "--pull-never", "-f", "build/squash/Dockerfile.squash-c", "--squash-all", "--layers", "-t", "test-squash-d:latest", "build/squash"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"inspect", "--format", "{{.RootFS.Layers}}", "test-squash-d"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ // Check for one layers
+ Expect(strings.Fields(session.OutputToString())).To(HaveLen(1))
+
+ // Second build must use last squashed build from cache
+ session = podmanTest.Podman([]string{"build", "--pull-never", "-f", "build/squash/Dockerfile.squash-c", "--squash-all", "--layers", "-t", "test", "build/squash"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ // Test if entire build is used from cache
+ Expect(session.OutputToString()).To(ContainSubstring("Using cache"))
+
+ session = podmanTest.Podman([]string{"inspect", "--format", "{{.RootFS.Layers}}", "test-squash-d"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ // Check for one layers
+ Expect(strings.Fields(session.OutputToString())).To(HaveLen(1))
+
+ })
+
It("podman build Containerfile locations", func() {
// Given
// Switch to temp dir and restore it afterwards
@@ -529,7 +555,7 @@ subdir**`
dd := exec.Command("dd", "if=/dev/random", "of="+randomFile, "bs=1G", "count=1")
ddSession, err := Start(dd, GinkgoWriter, GinkgoWriter)
Expect(err).ToNot(HaveOccurred())
- Eventually(ddSession).Should(Exit(0))
+ Eventually(ddSession, "10s", "1s").Should(Exit(0))
// make cwd as context root path
Expect(os.Chdir(contextDir)).ToNot(HaveOccurred())
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index 787178cd3..5ccafeb37 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -23,10 +23,31 @@ import (
func getRunString(input []string) []string {
// CRIU does not work with seccomp correctly on RHEL7 : seccomp=unconfined
- runString := []string{"run", "-it", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()}
+ runString := []string{"run", "--security-opt", "seccomp=unconfined", "-d", "--ip", GetRandomIPAddress()}
return append(runString, input...)
}
+// FIXME FIXME FIXME: workaround for #14653, please remove this function
+// and all calls to it once that bug is fixed.
+func fixmeFixme14653(podmanTest *PodmanTestIntegration, cid string) {
+ if !IsRemote() {
+ // Race condition only affects podman-remote
+ return
+ }
+
+ // Wait for container to truly go away
+ for i := 0; i < 5; i++ {
+ ps := podmanTest.Podman([]string{"container", "exists", cid})
+ ps.WaitWithDefaultTimeout()
+ if ps.ExitCode() == 1 {
+ // yay, it's gone
+ return
+ }
+ time.Sleep(time.Second)
+ }
+ // Fall through. Container still exists, but return anyway.
+}
+
var _ = Describe("Podman checkpoint", func() {
var (
tempdir string
@@ -318,7 +339,7 @@ var _ = Describe("Podman checkpoint", func() {
It("podman checkpoint container with established tcp connections", func() {
// Broken on Ubuntu.
SkipIfNotFedora()
- localRunString := getRunString([]string{redis})
+ localRunString := getRunString([]string{REDIS_IMAGE})
session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -478,6 +499,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -530,6 +552,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -548,6 +571,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -566,6 +590,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -584,6 +609,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -645,6 +671,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -676,8 +703,8 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during restore", func() {
// Start the container
- localRunString := getRunString([]string{"--rm", ALPINE, "top"})
- session := podmanTest.Podman(localRunString)
+ // test that restore works without network namespace (https://github.com/containers/podman/issues/14389)
+ session := podmanTest.Podman([]string{"run", "--network=none", "-d", "--rm", ALPINE, "top"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
@@ -694,6 +721,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -735,6 +763,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -772,6 +801,7 @@ var _ = Describe("Podman checkpoint", func() {
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -821,6 +851,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -890,6 +921,7 @@ var _ = Describe("Podman checkpoint", func() {
result = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointFileName})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1020,7 +1052,7 @@ var _ = Describe("Podman checkpoint", func() {
It("podman checkpoint and restore container with different port mappings", func() {
randomPort, err := utils.GetRandomPort()
Expect(err).ShouldNot(HaveOccurred())
- localRunString := getRunString([]string{"-p", fmt.Sprintf("%d:6379", randomPort), "--rm", redis})
+ localRunString := getRunString([]string{"-p", fmt.Sprintf("%d:6379", randomPort), "--rm", REDIS_IMAGE})
session := podmanTest.Podman(localRunString)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -1044,6 +1076,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1140,6 +1173,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).To(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
Expect(podmanTest.NumberOfContainers()).To(Equal(1))
@@ -1252,6 +1286,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1296,6 +1331,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1324,11 +1360,11 @@ var _ = Describe("Podman checkpoint", func() {
})
It("podman checkpoint and restore containers with --print-stats", func() {
- session1 := podmanTest.Podman(getRunString([]string{redis}))
+ session1 := podmanTest.Podman(getRunString([]string{REDIS_IMAGE}))
session1.WaitWithDefaultTimeout()
Expect(session1).Should(Exit(0))
- session2 := podmanTest.Podman(getRunString([]string{redis, "top"}))
+ session2 := podmanTest.Podman(getRunString([]string{REDIS_IMAGE, "top"}))
session2.WaitWithDefaultTimeout()
Expect(session2).Should(Exit(0))
@@ -1489,6 +1525,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1518,6 +1555,93 @@ var _ = Describe("Podman checkpoint", func() {
os.Remove(fileName)
})
+ It("podman checkpoint container with export and verify non-default runtime", func() {
+ SkipIfRemote("podman-remote does not support --runtime flag")
+ // This test triggers the edge case where:
+ // 1. Default runtime is crun
+ // 2. Container is created with runc
+ // 3. Checkpoint without setting --runtime into archive
+ // 4. Restore without setting --runtime from archive
+ // It should be expected that podman identifies runtime
+ // from the checkpoint archive.
+
+ // Prevent --runtime arg from being set to force using default
+ // runtime unless explicitly set through passed args.
+ preservedMakeOptions := podmanTest.PodmanMakeOptions
+ podmanTest.PodmanMakeOptions = func(args []string, noEvents, noCache bool) []string {
+ defaultArgs := preservedMakeOptions(args, noEvents, noCache)
+ for i := range args {
+ // Runtime is set explicitly, so we should keep --runtime arg.
+ if args[i] == "--runtime" {
+ return defaultArgs
+ }
+ }
+ updatedArgs := make([]string, 0)
+ for i := 0; i < len(defaultArgs); i++ {
+ // Remove --runtime arg, letting podman fall back to its default
+ if defaultArgs[i] == "--runtime" {
+ i++
+ } else {
+ updatedArgs = append(updatedArgs, defaultArgs[i])
+ }
+ }
+ return updatedArgs
+ }
+
+ for _, runtime := range []string{"runc", "crun"} {
+ if err := exec.Command(runtime, "--help").Run(); err != nil {
+ Skip(fmt.Sprintf("%s not found in PATH; this test requires both runc and crun", runtime))
+ }
+ }
+
+ // Detect default runtime
+ session := podmanTest.Podman([]string{"info", "--format", "{{.Host.OCIRuntime.Name}}"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ if defaultRuntime := session.OutputToString(); defaultRuntime != "crun" {
+ Skip(fmt.Sprintf("Default runtime is %q; this test requires crun to be default", defaultRuntime))
+ }
+
+ // Force non-default runtime "runc"
+ localRunString := getRunString([]string{"--runtime", "runc", "--rm", ALPINE, "top"})
+ session = podmanTest.Podman(localRunString)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ cid := session.OutputToString()
+
+ session = podmanTest.Podman([]string{"inspect", "--format", "{{.OCIRuntime}}", cid})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(Equal("runc"))
+
+ checkpointExportPath := "/tmp/checkpoint-" + cid + ".tar.gz"
+
+ session = podmanTest.Podman([]string{"container", "checkpoint", cid, "-e", checkpointExportPath})
+ session.WaitWithDefaultTimeout()
+ // As the container has been started with '--rm' it will be completely
+ // cleaned up after checkpointing.
+ Expect(session).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"container", "restore", "-i", checkpointExportPath})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring("Up"))
+
+ // The restored container should have the same runtime as the original container
+ session = podmanTest.Podman([]string{"inspect", "--format", "{{.OCIRuntime}}", cid})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(Equal("runc"))
+
+ // Remove exported checkpoint
+ os.Remove(checkpointExportPath)
+ })
+
It("podman checkpoint container with export and try to change the runtime", func() {
SkipIfRemote("podman-remote does not support --runtime flag")
// This test will only run if runc and crun both exist
@@ -1573,6 +1697,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
@@ -1651,6 +1776,7 @@ var _ = Describe("Podman checkpoint", func() {
// As the container has been started with '--rm' it will be completely
// cleaned up after checkpointing.
Expect(result).Should(Exit(0))
+ fixmeFixme14653(podmanTest, cid)
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.NumberOfContainers()).To(Equal(0))
diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go
index c82e5e471..452a378c2 100644
--- a/test/e2e/commit_test.go
+++ b/test/e2e/commit_test.go
@@ -362,7 +362,7 @@ var _ = Describe("Podman commit", func() {
Expect(images[0].Config.ExposedPorts).To(HaveKey("80/tcp"))
name = "testcon2"
- s = podmanTest.Podman([]string{"run", "--name", name, "-d", nginx})
+ s = podmanTest.Podman([]string{"run", "--name", name, "-d", NGINX_IMAGE})
s.WaitWithDefaultTimeout()
Expect(s).Should(Exit(0))
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index db194b777..43367cf63 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -2,6 +2,7 @@ package integration
import (
"bytes"
+ "errors"
"fmt"
"io/ioutil"
"math/rand"
@@ -30,18 +31,17 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
- "github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
var (
//lint:ignore ST1003
- PODMAN_BINARY string //nolint:revive,stylecheck
- INTEGRATION_ROOT string //nolint:revive,stylecheck
- CGROUP_MANAGER = "systemd" //nolint:revive,stylecheck
- RESTORE_IMAGES = []string{ALPINE, BB, nginx} //nolint:revive,stylecheck
+ PODMAN_BINARY string //nolint:revive,stylecheck
+ INTEGRATION_ROOT string //nolint:revive,stylecheck
+ CGROUP_MANAGER = "systemd" //nolint:revive,stylecheck
+ RESTORE_IMAGES = []string{ALPINE, BB, NGINX_IMAGE} //nolint:revive,stylecheck
defaultWaitTimeout = 90
- CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode() //nolint:revive,stylecheck
+ CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode()
)
// PodmanTestIntegration struct for command line options
@@ -115,7 +115,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
podman := PodmanTestSetup("/tmp")
// Pull cirros but don't put it into the cache
- pullImages := []string{cirros, fedoraToolbox, volumeTest}
+ pullImages := []string{CIRROS_IMAGE, fedoraToolbox, volumeTest}
pullImages = append(pullImages, CACHE_IMAGES...)
for _, image := range pullImages {
podman.createArtifact(image)
@@ -322,7 +322,7 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
}
}
- // Setup registries.conf ENV variable
+ // Set up registries.conf ENV variable
p.setDefaultRegistriesConfigEnv()
// Rewrite the PodmanAsUser function
p.PodmanMakeOptions = p.makeOptions
@@ -464,7 +464,7 @@ func (p *PodmanTestIntegration) RunNginxWithHealthCheck(name string) (*PodmanSes
podmanArgs = append(podmanArgs, "--name", name)
}
// curl without -f exits 0 even if http code >= 400!
- podmanArgs = append(podmanArgs, "-dt", "-P", "--health-cmd", "curl -f http://localhost/", nginx)
+ podmanArgs = append(podmanArgs, "-dt", "-P", "--health-cmd", "curl -f http://localhost/", NGINX_IMAGE)
session := p.Podman(podmanArgs)
session.WaitWithDefaultTimeout()
return session, session.OutputToString()
@@ -618,14 +618,14 @@ func (p *PodmanTestIntegration) RunHealthCheck(cid string) error {
restart := p.Podman([]string{"restart", cid})
restart.WaitWithDefaultTimeout()
if restart.ExitCode() != 0 {
- return errors.Errorf("unable to restart %s", cid)
+ return fmt.Errorf("unable to restart %s", cid)
}
}
}
fmt.Printf("Waiting for %s to pass healthcheck\n", cid)
time.Sleep(1 * time.Second)
}
- return errors.Errorf("unable to detect %s as running", cid)
+ return fmt.Errorf("unable to detect %s as running", cid)
}
func (p *PodmanTestIntegration) CreateSeccompJSON(in []byte) (string, error) {
@@ -1042,18 +1042,15 @@ var IPRegex = `(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|[01
// digShort execs into the given container and does a dig lookup with a timeout
// backoff. If it gets a response, it ensures that the output is in the correct
// format and iterates a string array for match
-func digShort(container, lookupName string, matchNames []string, p *PodmanTestIntegration) {
+func digShort(container, lookupName, expectedIP string, p *PodmanTestIntegration) {
digInterval := time.Millisecond * 250
for i := 0; i < 6; i++ {
time.Sleep(digInterval * time.Duration(i))
dig := p.Podman([]string{"exec", container, "dig", "+short", lookupName})
dig.WaitWithDefaultTimeout()
- if dig.ExitCode() == 0 {
- output := dig.OutputToString()
- Expect(output).To(MatchRegexp(IPRegex))
- for _, name := range matchNames {
- Expect(output).To(Equal(name))
- }
+ output := dig.OutputToString()
+ if dig.ExitCode() == 0 && output != "" {
+ Expect(output).To(Equal(expectedIP))
// success
return
}
@@ -1064,13 +1061,13 @@ func digShort(container, lookupName string, matchNames []string, p *PodmanTestIn
// WaitForFile to be created in defaultWaitTimeout seconds, returns false if file not created
func WaitForFile(path string) (err error) {
until := time.Now().Add(time.Duration(defaultWaitTimeout) * time.Second)
- for i := 1; time.Now().Before(until); i++ {
+ for time.Now().Before(until) {
_, err = os.Stat(path)
switch {
case err == nil:
return nil
case errors.Is(err, os.ErrNotExist):
- time.Sleep(time.Duration(i) * time.Second)
+ time.Sleep(10 * time.Millisecond)
default:
return err
}
@@ -1078,18 +1075,21 @@ func WaitForFile(path string) (err error) {
return err
}
-// WaitForService blocks, waiting for some service listening on given host:port
+// WaitForService blocks for defaultWaitTimeout seconds, waiting for some service listening on given host:port
func WaitForService(address url.URL) {
// Wait for podman to be ready
- var conn net.Conn
var err error
- for i := 1; i <= 5; i++ {
+ until := time.Now().Add(time.Duration(defaultWaitTimeout) * time.Second)
+ for time.Now().Before(until) {
+ var conn net.Conn
conn, err = net.Dial("tcp", address.Host)
- if err != nil {
- // Podman not available yet...
- time.Sleep(time.Duration(i) * time.Second)
+ if err == nil {
+ conn.Close()
+ break
}
+
+ // Podman not available yet...
+ time.Sleep(10 * time.Millisecond)
}
Expect(err).ShouldNot(HaveOccurred())
- conn.Close()
}
diff --git a/test/e2e/config.go b/test/e2e/config.go
index 2ca8e2a15..a8dd6301f 100644
--- a/test/e2e/config.go
+++ b/test/e2e/config.go
@@ -1,7 +1,7 @@
package integration
var (
- redis = "quay.io/libpod/redis:alpine"
+ REDIS_IMAGE = "quay.io/libpod/redis:alpine" //nolint:revive,stylecheck
fedoraMinimal = "registry.fedoraproject.org/fedora-minimal:34"
ALPINE = "quay.io/libpod/alpine:latest"
ALPINELISTTAG = "quay.io/libpod/alpine:3.10.2"
@@ -10,12 +10,12 @@ var (
ALPINEAMD64ID = "961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4"
ALPINEARM64DIGEST = "quay.io/libpod/alpine@sha256:f270dcd11e64b85919c3bab66886e59d677cf657528ac0e4805d3c71e458e525"
ALPINEARM64ID = "915beeae46751fc564998c79e73a1026542e945ca4f73dc841d09ccc6c2c0672"
- infra = "k8s.gcr.io/pause:3.2"
+ INFRA_IMAGE = "k8s.gcr.io/pause:3.2" //nolint:revive,stylecheck
BB = "quay.io/libpod/busybox:latest"
- healthcheck = "quay.io/libpod/alpine_healthcheck:latest"
+ HEALTHCHECK_IMAGE = "quay.io/libpod/alpine_healthcheck:latest" //nolint:revive,stylecheck
ImageCacheDir = "/tmp/podman/imagecachedir"
fedoraToolbox = "registry.fedoraproject.org/fedora-toolbox:36"
- volumeTest = "quay.io/libpod/volume-plugin-test-img:latest"
+ volumeTest = "quay.io/libpod/volume-plugin-test-img:20220623"
// This image has seccomp profiles that blocks all syscalls.
// The intention behind blocking all syscalls is to prevent
diff --git a/test/e2e/config_amd64.go b/test/e2e/config_amd64.go
index c4cb97b2e..f32542df8 100644
--- a/test/e2e/config_amd64.go
+++ b/test/e2e/config_amd64.go
@@ -1,16 +1,16 @@
package integration
var (
- STORAGE_FS = "vfs" //nolint:revive,stylecheck
- 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, redis, registry, infra, labels, healthcheck, UBI_INIT, UBI_MINIMAL, fedoraToolbox} //nolint:revive,stylecheck
- nginx = "quay.io/libpod/alpine_nginx:latest"
- BB_GLIBC = "docker.io/library/busybox:glibc" //nolint:revive,stylecheck
- registry = "quay.io/libpod/registry:2.6"
- labels = "quay.io/libpod/alpine_labels:latest"
- UBI_MINIMAL = "registry.access.redhat.com/ubi8-minimal" //nolint:revive,stylecheck
- UBI_INIT = "registry.access.redhat.com/ubi8-init" //nolint:revive,stylecheck
- cirros = "quay.io/libpod/cirros:latest"
+ STORAGE_FS = "vfs" //nolint:revive,stylecheck
+ 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, UBI_INIT, UBI_MINIMAL, 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.6" //nolint:revive,stylecheck
+ LABELS_IMAGE = "quay.io/libpod/alpine_labels:latest" //nolint:revive,stylecheck
+ UBI_MINIMAL = "registry.access.redhat.com/ubi8-minimal" //nolint:revive,stylecheck
+ UBI_INIT = "registry.access.redhat.com/ubi8-init" //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 569a34efb..a4bec748a 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, redis, infra, labels}
- nginx = "quay.io/libpod/alpine_nginx-ppc64le:latest"
+ CACHE_IMAGES = []string{ALPINE, BB, fedoraMinimal, NGINX_IMAGE, REDIS_IMAGE, INFRA_IMAGE, LABELS_IMAGE}
+ NGINX_IMAGE = "quay.io/libpod/alpine_nginx-ppc64le:latest"
BB_GLIBC = "docker.io/ppc64le/busybox:glibc"
- labels = "quay.io/libpod/alpine_labels-ppc64le:latest"
- registry string
+ LABELS_IMAGE = "quay.io/libpod/alpine_labels-ppc64le:latest"
+ REGISTRY_IMAGE string
)
diff --git a/test/e2e/container_inspect_test.go b/test/e2e/container_inspect_test.go
index 5aed943da..436c60c05 100644
--- a/test/e2e/container_inspect_test.go
+++ b/test/e2e/container_inspect_test.go
@@ -58,7 +58,7 @@ var _ = Describe("Podman container inspect", func() {
It("podman inspect shows exposed ports on image", func() {
name := "testcon"
- session := podmanTest.Podman([]string{"run", "-d", "--expose", "8989", "--name", name, nginx})
+ session := podmanTest.Podman([]string{"run", "-d", "--expose", "8989", "--name", name, NGINX_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go
index 6fd88753b..85cc5023c 100644
--- a/test/e2e/create_staticip_test.go
+++ b/test/e2e/create_staticip_test.go
@@ -25,7 +25,7 @@ var _ = Describe("Podman create with --ip flag", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
- // Cleanup the CNI networks used by the tests
+ // Clean up the CNI networks used by the tests
os.RemoveAll("/var/lib/cni/networks/podman")
})
diff --git a/test/e2e/create_staticmac_test.go b/test/e2e/create_staticmac_test.go
index f02d9c88b..32deb04a8 100644
--- a/test/e2e/create_staticmac_test.go
+++ b/test/e2e/create_staticmac_test.go
@@ -25,7 +25,7 @@ var _ = Describe("Podman run with --mac-address flag", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
- // Cleanup the CNI networks used by the tests
+ // Clean up the CNI networks used by the tests
os.RemoveAll("/var/lib/cni/networks/podman")
})
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 63544d579..9679aad24 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -63,7 +63,7 @@ var _ = Describe("Podman create", func() {
lock := GetPortLock("5000")
defer lock.Unlock()
- session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
+ session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -273,7 +273,7 @@ var _ = Describe("Podman create", func() {
It("podman run entrypoint and cmd test", func() {
name := "test101"
- create := podmanTest.Podman([]string{"create", "--name", name, redis})
+ create := podmanTest.Podman([]string{"create", "--name", name, REDIS_IMAGE})
create.WaitWithDefaultTimeout()
Expect(create).Should(Exit(0))
@@ -560,7 +560,7 @@ var _ = Describe("Podman create", func() {
session = podmanTest.Podman([]string{"create", "--umask", "9999", "--name", "bad", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
- Expect(session.ErrorToString()).To(ContainSubstring("Invalid umask"))
+ Expect(session.ErrorToString()).To(ContainSubstring("invalid umask"))
})
It("create container in pod with IP should fail", func() {
diff --git a/test/e2e/events_test.go b/test/e2e/events_test.go
index 725118ab0..528fa143d 100644
--- a/test/e2e/events_test.go
+++ b/test/e2e/events_test.go
@@ -216,4 +216,25 @@ var _ = Describe("Podman events", func() {
Expect(result.OutputToString()).To(ContainSubstring("create"))
})
+ It("podman events health_status generated", func() {
+ session := podmanTest.Podman([]string{"run", "--name", "test-hc", "-dt", "--health-cmd", "echo working", "busybox"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ for i := 0; i < 5; i++ {
+ hc := podmanTest.Podman([]string{"healthcheck", "run", "test-hc"})
+ hc.WaitWithDefaultTimeout()
+ exitCode := hc.ExitCode()
+ if exitCode == 0 || i == 4 {
+ break
+ }
+ time.Sleep(1 * time.Second)
+ }
+
+ result := podmanTest.Podman([]string{"events", "--stream=false", "--filter", "event=health_status"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(len(result.OutputToStringArray())).To(BeNumerically(">=", 1), "Number of health_status events")
+ })
+
})
diff --git a/test/e2e/generate_systemd_test.go b/test/e2e/generate_systemd_test.go
index 08e8fbc8c..45a2f1f86 100644
--- a/test/e2e/generate_systemd_test.go
+++ b/test/e2e/generate_systemd_test.go
@@ -111,7 +111,7 @@ var _ = Describe("Podman generate systemd", func() {
})
It("podman generate systemd", func() {
- n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", nginx})
+ n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", NGINX_IMAGE})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
@@ -124,7 +124,7 @@ var _ = Describe("Podman generate systemd", func() {
})
It("podman generate systemd --files --name", func() {
- n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", nginx})
+ n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", NGINX_IMAGE})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
@@ -139,7 +139,7 @@ var _ = Describe("Podman generate systemd", func() {
})
It("podman generate systemd with timeout", func() {
- n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", nginx})
+ n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", NGINX_IMAGE})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
@@ -159,7 +159,7 @@ var _ = Describe("Podman generate systemd", func() {
})
It("podman generate systemd with user-defined dependencies", func() {
- n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", nginx})
+ n := podmanTest.Podman([]string{"run", "--name", "nginx", "-dt", NGINX_IMAGE})
n.WaitWithDefaultTimeout()
Expect(n).Should(Exit(0))
diff --git a/test/e2e/healthcheck_run_test.go b/test/e2e/healthcheck_run_test.go
index add739988..fd4e763f9 100644
--- a/test/e2e/healthcheck_run_test.go
+++ b/test/e2e/healthcheck_run_test.go
@@ -45,7 +45,7 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman disable healthcheck with --no-healthcheck on valid container", func() {
- session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck})
+ session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", HEALTHCHECK_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
@@ -54,7 +54,7 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman disable healthcheck with --no-healthcheck must not show starting on status", func() {
- session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", healthcheck})
+ session := podmanTest.Podman([]string{"run", "-dt", "--no-healthcheck", "--name", "hc", HEALTHCHECK_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
hc := podmanTest.Podman([]string{"container", "inspect", "--format", "{{.State.Health.Status}}", "hc"})
@@ -98,7 +98,7 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman disable healthcheck with --health-cmd=none on valid container", func() {
- session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "none", "--name", "hc", healthcheck})
+ session := podmanTest.Podman([]string{"run", "-dt", "--health-cmd", "none", "--name", "hc", HEALTHCHECK_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
hc := podmanTest.Podman([]string{"healthcheck", "run", "hc"})
@@ -108,7 +108,7 @@ var _ = Describe("Podman healthcheck run", func() {
It("podman healthcheck on valid container", func() {
Skip("Extremely consistent flake - re-enable on debugging")
- session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck})
+ session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", HEALTHCHECK_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -143,7 +143,7 @@ var _ = Describe("Podman healthcheck run", func() {
})
It("podman healthcheck on stopped container", func() {
- session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", healthcheck, "ls"})
+ session := podmanTest.Podman([]string{"run", "-dt", "--name", "hc", HEALTHCHECK_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/image_scp_test.go b/test/e2e/image_scp_test.go
index 2ad3cc75e..77fe810bd 100644
--- a/test/e2e/image_scp_test.go
+++ b/test/e2e/image_scp_test.go
@@ -22,12 +22,10 @@ var _ = Describe("podman image scp", func() {
)
BeforeEach(func() {
-
ConfPath.Value, ConfPath.IsSet = os.LookupEnv("CONTAINERS_CONF")
conf, err := ioutil.TempFile("", "containersconf")
- if err != nil {
- panic(err)
- }
+ Expect(err).ToNot(HaveOccurred())
+
os.Setenv("CONTAINERS_CONF", conf.Name())
tempdir, err = CreateTempDirInTempDir()
if err != nil {
@@ -52,42 +50,40 @@ var _ = Describe("podman image scp", func() {
})
It("podman image scp bogus image", func() {
- if IsRemote() {
- Skip("this test is only for non-remote")
- }
scp := podmanTest.Podman([]string{"image", "scp", "FOOBAR"})
scp.WaitWithDefaultTimeout()
- Expect(scp).To(ExitWithError())
+ Expect(scp).Should(ExitWithError())
})
It("podman image scp with proper connection", func() {
- if IsRemote() {
- Skip("this test is only for non-remote")
- }
cmd := []string{"system", "connection", "add",
"--default",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
- Expect(session).To(Exit(0))
+ Expect(session).Should(Exit(0))
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
- Expect(cfg.Engine).To(HaveField("ActiveService", "QA"))
+ Expect(cfg.Engine).Should(HaveField("ActiveService", "QA"))
Expect(cfg.Engine.ServiceDestinations).To(HaveKeyWithValue("QA",
config.Destination{
- URI: "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ URI: "ssh://root@podman.test:2222/run/podman/podman.sock",
},
))
scp := podmanTest.Podman([]string{"image", "scp", ALPINE, "QA::"})
- scp.Wait(45)
+ scp.WaitWithDefaultTimeout()
// exit with error because we cannot make an actual ssh connection
// This tests that the input we are given is validated and prepared correctly
- // The error given should either be a missing image (due to testing suite complications) or a i/o timeout on ssh
- Expect(scp).To(ExitWithError())
+ // The error given should either be a missing image (due to testing suite complications) or a no such host timeout on ssh
+ Expect(scp).Should(ExitWithError())
+ // podman-remote exits with a different error
+ if !IsRemote() {
+ Expect(scp.ErrorToString()).Should(ContainSubstring("no such host"))
+ }
})
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 6fe850f0b..1ce2fa93d 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -182,8 +182,8 @@ var _ = Describe("Podman inspect", func() {
})
It("podman inspect shows healthcheck on docker image", func() {
- podmanTest.AddImageToRWStore(healthcheck)
- session := podmanTest.Podman([]string{"inspect", "--format=json", healthcheck})
+ podmanTest.AddImageToRWStore(HEALTHCHECK_IMAGE)
+ session := podmanTest.Podman([]string{"inspect", "--format=json", HEALTHCHECK_IMAGE})
session.WaitWithDefaultTimeout()
imageData := session.InspectImageJSON()
Expect(imageData[0].HealthCheck.Timeout).To(BeNumerically("==", 3000000000))
diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go
index 552a7c15d..2a9a86729 100644
--- a/test/e2e/kill_test.go
+++ b/test/e2e/kill_test.go
@@ -128,6 +128,26 @@ var _ = Describe("Podman kill", func() {
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
})
+ It("podman kill paused container", func() {
+ ctrName := "testctr"
+ session := podmanTest.RunTopContainer(ctrName)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ pause := podmanTest.Podman([]string{"pause", ctrName})
+ pause.WaitWithDefaultTimeout()
+ Expect(pause).Should(Exit(0))
+
+ kill := podmanTest.Podman([]string{"kill", ctrName})
+ kill.WaitWithDefaultTimeout()
+ Expect(kill).Should(Exit(0))
+
+ inspect := podmanTest.Podman([]string{"inspect", "-f", "{{.State.Status}}", ctrName})
+ inspect.WaitWithDefaultTimeout()
+ Expect(inspect).Should(Exit(0))
+ Expect(inspect.OutputToString()).To(Or(Equal("stopped"), Equal("exited")))
+ })
+
It("podman kill --cidfile", func() {
tmpDir, err := ioutil.TempDir("", "")
Expect(err).To(BeNil())
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index a633bd3d7..ecb7a2278 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -76,3 +76,8 @@ func (p *PodmanTestIntegration) StopRemoteService() {}
// We don't support running API service when local
func (p *PodmanTestIntegration) StartRemoteService() {
}
+
+// Just a stub for compiling with `!remote`.
+func getRemoteOptions(p *PodmanTestIntegration, args []string) []string {
+ return nil
+}
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 4e6dcb8af..14dd6b6b8 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -8,6 +8,7 @@ import (
"time"
. "github.com/containers/podman/v4/test/utils"
+ "github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -102,12 +103,12 @@ var _ = Describe("Podman logs", func() {
It("tail 99 lines: "+log, func() {
skipIfJournaldInContainer()
- logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
+ name := "test1"
+ logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
- cid := logc.OutputToString()
- results := podmanTest.Podman([]string{"logs", "--tail", "99", cid})
+ results := podmanTest.Podman([]string{"logs", "--tail", "99", name})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
Expect(results.OutputToStringArray()).To(HaveLen(3))
@@ -116,11 +117,17 @@ var _ = Describe("Podman logs", func() {
It("tail 800 lines: "+log, func() {
skipIfJournaldInContainer()
+ // this uses -d so that we do not have 1000 unnecessary lines printed in every test log
logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"})
logc.WaitWithDefaultTimeout()
Expect(logc).To(Exit(0))
cid := logc.OutputToString()
+ // make sure we wait for the container to finish writing its output
+ wait := podmanTest.Podman([]string{"wait", cid})
+ wait.WaitWithDefaultTimeout()
+ Expect(wait).To(Exit(0))
+
results := podmanTest.Podman([]string{"logs", "--tail", "800", cid})
results.WaitWithDefaultTimeout()
Expect(results).To(Exit(0))
@@ -364,6 +371,26 @@ var _ = Describe("Podman logs", func() {
Expect(results.OutputToString()).To(Equal("stdout"))
Expect(results.ErrorToString()).To(Equal("stderr"))
})
+
+ It("podman logs partial log lines: "+log, func() {
+ skipIfJournaldInContainer()
+
+ cname := "log-test"
+ content := stringid.GenerateNonCryptoID()
+ // use printf to print no extra newline
+ logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "printf", content})
+ logc.WaitWithDefaultTimeout()
+ Expect(logc).To(Exit(0))
+ // Important: do not use OutputToString(), this will remove the trailing newline from the output.
+ // However this test must make sure that there is no such extra newline.
+ Expect(string(logc.Out.Contents())).To(Equal(content))
+
+ logs := podmanTest.Podman([]string{"logs", cname})
+ logs.WaitWithDefaultTimeout()
+ Expect(logs).To(Exit(0))
+ // see comment above
+ Expect(string(logs.Out.Contents())).To(Equal(content))
+ })
}
It("using journald for container with container tag", func() {
diff --git a/test/e2e/manifest_test.go b/test/e2e/manifest_test.go
index 88ccdc87d..1f58419a1 100644
--- a/test/e2e/manifest_test.go
+++ b/test/e2e/manifest_test.go
@@ -42,7 +42,6 @@ var _ = Describe("Podman manifest", func() {
podmanTest.Cleanup()
f := CurrentGinkgoTestDescription()
processTestResult(f)
-
})
It("create w/o image", func() {
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
@@ -91,6 +90,27 @@ var _ = Describe("Podman manifest", func() {
Expect(session.OutputToString()).To(ContainSubstring(imageListARM64InstanceDigest))
})
+ It("add with new version", func() {
+ // Following test must pass for both podman and podman-remote
+ session := podmanTest.Podman([]string{"manifest", "create", "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ id := strings.TrimSpace(string(session.Out.Contents()))
+
+ session = podmanTest.Podman([]string{"manifest", "inspect", id})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"manifest", "add", "--os-version", "7.7.7", "foo", imageListInstance})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"manifest", "inspect", "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring("7.7.7"))
+ })
+
It("tag", func() {
session := podmanTest.Podman([]string{"manifest", "create", "foobar"})
session.WaitWithDefaultTimeout()
@@ -274,10 +294,23 @@ var _ = Describe("Podman manifest", func() {
It("authenticated push", func() {
registryOptions := &podmanRegistry.Options{
- Image: "docker-archive:" + imageTarPath(registry),
+ Image: "docker-archive:" + imageTarPath(REGISTRY_IMAGE),
+ }
+
+ // registry script invokes $PODMAN; make sure we define that
+ // so it can use our same networking options.
+ opts := strings.Join(podmanTest.MakeOptions(nil, false, false), " ")
+ if IsRemote() {
+ opts = strings.Join(getRemoteOptions(podmanTest, nil), " ")
}
+ os.Setenv("PODMAN", podmanTest.PodmanBinary+" "+opts)
registry, err := podmanRegistry.StartWithOptions(registryOptions)
Expect(err).To(BeNil())
+ defer func() {
+ err := registry.Stop()
+ Expect(err).To(BeNil())
+ os.Unsetenv("PODMAN")
+ }()
session := podmanTest.Podman([]string{"manifest", "create", "foo"})
session.WaitWithDefaultTimeout()
@@ -306,9 +339,6 @@ var _ = Describe("Podman manifest", func() {
push = podmanTest.Podman([]string{"manifest", "push", "--tls-verify=false", "--creds=podmantest:wrongpasswd", "foo", "localhost:" + registry.Port + "/credstest"})
push.WaitWithDefaultTimeout()
Expect(push).To(ExitWithError())
-
- err = registry.Stop()
- Expect(err).To(BeNil())
})
It("push with error", func() {
@@ -384,4 +414,32 @@ var _ = Describe("Podman manifest", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
+
+ It("manifest rm should not remove image and should be able to remove tagged manifest list", func() {
+ // manifest rm should fail with `image is not a manifest list`
+ session := podmanTest.Podman([]string{"manifest", "rm", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(125))
+ Expect(session.ErrorToString()).To(ContainSubstring("image is not a manifest list"))
+
+ manifestName := "testmanifest:sometag"
+ session = podmanTest.Podman([]string{"manifest", "create", manifestName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // verify if manifest exists
+ session = podmanTest.Podman([]string{"manifest", "exists", manifestName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // manifest rm should be able to remove tagged manifest list
+ session = podmanTest.Podman([]string{"manifest", "rm", manifestName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // verify that manifest should not exist
+ session = podmanTest.Podman([]string{"manifest", "exists", manifestName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(1))
+ })
})
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index a0716c84d..c9ffe6a8d 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -2,7 +2,6 @@ package integration
import (
"os"
- "strings"
. "github.com/containers/podman/v4/test/utils"
"github.com/containers/storage/pkg/stringid"
@@ -94,7 +93,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec2 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec2.WaitWithDefaultTimeout()
Expect(exec2).Should(Exit(0))
- Expect(strings.Contains(exec2.OutputToString(), ns)).To(BeTrue())
+ Expect(exec2.OutputToString()).To(ContainSubstring(ns))
dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"})
dis.WaitWithDefaultTimeout()
@@ -113,7 +112,12 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec3 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec3.WaitWithDefaultTimeout()
Expect(exec3).Should(Exit(0))
- Expect(strings.Contains(exec3.OutputToString(), ns)).To(BeFalse())
+ Expect(exec3.OutputToString()).ToNot(ContainSubstring(ns))
+
+ // make sure stats still works https://github.com/containers/podman/issues/13824
+ stats := podmanTest.Podman([]string{"stats", "test", "--no-stream"})
+ stats.WaitWithDefaultTimeout()
+ Expect(stats).Should(Exit(0))
})
It("bad network name in connect should result in error", func() {
@@ -206,7 +210,7 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec2 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec2.WaitWithDefaultTimeout()
Expect(exec2).Should(Exit(0))
- Expect(strings.Contains(exec2.OutputToString(), ns)).To(BeFalse())
+ Expect(exec2.OutputToString()).ToNot(ContainSubstring(ns))
ip := "10.11.100.99"
mac := "44:11:44:11:44:11"
@@ -235,7 +239,12 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec3 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"})
exec3.WaitWithDefaultTimeout()
Expect(exec3).Should(Exit(0))
- Expect(strings.Contains(exec3.OutputToString(), ns)).To(BeTrue())
+ Expect(exec3.OutputToString()).To(ContainSubstring(ns))
+
+ // make sure stats works https://github.com/containers/podman/issues/13824
+ stats := podmanTest.Podman([]string{"stats", "test", "--no-stream"})
+ stats.WaitWithDefaultTimeout()
+ Expect(stats).Should(Exit(0))
// make sure no logrus errors are shown https://github.com/containers/podman/issues/9602
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index 715455521..d4f60d3e4 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -163,6 +163,26 @@ var _ = Describe("Podman network", func() {
Expect(session.OutputToString()).To(Not(ContainSubstring(name)))
})
+ It("podman network list --filter dangling", func() {
+ name, path := generateNetworkConfig(podmanTest)
+ defer removeConf(path)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=true"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring(name))
+
+ session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=false"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).NotTo(ContainSubstring(name))
+
+ session = podmanTest.Podman([]string{"network", "ls", "--filter", "dangling=foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring(`invalid dangling filter value "foo"`))
+ })
+
It("podman network ID test", func() {
net := "networkIDTest"
// the network id should be the sha256 hash of the network name
@@ -487,14 +507,14 @@ var _ = Describe("Podman network", func() {
interval *= 2
}
- top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx})
+ top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", NGINX_IMAGE})
top.WaitWithDefaultTimeout()
Expect(top).Should(Exit(0))
interval = 250 * time.Millisecond
// Wait for the nginx service to be running
for i := 0; i < 6; i++ {
// Test curl against the container's name
- c1 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web"})
+ c1 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web"})
c1.WaitWithDefaultTimeout()
worked = c1.ExitCode() == 0
if worked {
@@ -507,12 +527,12 @@ var _ = Describe("Podman network", func() {
// Nginx is now running so no need to do a loop
// Test against the first alias
- c2 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web1"})
+ c2 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web1"})
c2.WaitWithDefaultTimeout()
Expect(c2).Should(Exit(0))
// Test against the second alias
- c3 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web2"})
+ c3 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web2"})
c3.WaitWithDefaultTimeout()
Expect(c3).Should(Exit(0))
})
@@ -538,14 +558,14 @@ var _ = Describe("Podman network", func() {
interval *= 2
}
- top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx})
+ top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", NGINX_IMAGE})
top.WaitWithDefaultTimeout()
Expect(top).Should(Exit(0))
interval = 250 * time.Millisecond
// Wait for the nginx service to be running
for i := 0; i < 6; i++ {
// Test curl against the container's name
- c1 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web"})
+ c1 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web"})
c1.WaitWithDefaultTimeout()
worked = c1.ExitCode() == 0
if worked {
@@ -558,12 +578,12 @@ var _ = Describe("Podman network", func() {
// Nginx is now running so no need to do a loop
// Test against the first alias
- c2 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web1"})
+ c2 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web1"})
c2.WaitWithDefaultTimeout()
Expect(c2).Should(Exit(0))
// Test against the second alias
- c3 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, nginx, "curl", "web2"})
+ c3 := podmanTest.Podman([]string{"run", "--dns-search", "dns.podman", "--network=" + netName, NGINX_IMAGE, "curl", "web2"})
c3.WaitWithDefaultTimeout()
Expect(c3).Should(Exit(0))
})
diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go
index 402719de2..d677eddb0 100644
--- a/test/e2e/pause_test.go
+++ b/test/e2e/pause_test.go
@@ -82,7 +82,7 @@ var _ = Describe("Podman pause", func() {
// check we can read stats for a paused container
result = podmanTest.Podman([]string{"stats", "--no-stream", cid})
result.WaitWithDefaultTimeout()
- Expect(result).To(ExitWithError())
+ Expect(result).Should(Exit(0))
})
It("podman pause a running container by id", func() {
@@ -273,7 +273,7 @@ var _ = Describe("Podman pause", func() {
It("Pause a bunch of running containers", func() {
for i := 0; i < 3; i++ {
name := fmt.Sprintf("test%d", i)
- run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx})
+ run := podmanTest.Podman([]string{"run", "-dt", "--name", name, NGINX_IMAGE})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
@@ -300,7 +300,7 @@ var _ = Describe("Podman pause", func() {
It("Unpause a bunch of running containers", func() {
for i := 0; i < 3; i++ {
name := fmt.Sprintf("test%d", i)
- run := podmanTest.Podman([]string{"run", "-dt", "--name", name, nginx})
+ run := podmanTest.Podman([]string{"run", "-dt", "--name", name, NGINX_IMAGE})
run.WaitWithDefaultTimeout()
Expect(run).Should(Exit(0))
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 31044f68b..457aaebb2 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -1512,7 +1512,7 @@ var _ = Describe("Podman play kube", func() {
// If you do not supply command or args for a Container, the defaults defined in the Docker image are used.
It("podman play kube test correct args and cmd when not specified", func() {
- pod := getPod(withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil))))
+ pod := getPod(withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg(nil))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -1536,7 +1536,7 @@ var _ = Describe("Podman play kube", func() {
// If you supply a command but no args for a Container, only the supplied command is used.
// The default EntryPoint and the default Cmd defined in the Docker image are ignored.
It("podman play kube test correct command with only set command in yaml file", func() {
- pod := getPod(withCtr(getCtr(withImage(registry), withCmd([]string{"echo", "hello"}), withArg(nil))))
+ pod := getPod(withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd([]string{"echo", "hello"}), withArg(nil))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -1587,7 +1587,7 @@ var _ = Describe("Podman play kube", func() {
// If you supply only args for a Container, the default Entrypoint defined in the Docker image is run with the args that you supplied.
It("podman play kube test correct command with only set args in yaml file", func() {
- pod := getPod(withCtr(getCtr(withImage(registry), withCmd(nil), withArg([]string{"echo", "hello"}))))
+ pod := getPod(withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg([]string{"echo", "hello"}))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -1611,7 +1611,7 @@ var _ = Describe("Podman play kube", func() {
// the default Entrypoint and the default Cmd defined in the Docker image are ignored.
// Your command is run with your args.
It("podman play kube test correct command with both set args and cmd in yaml file", func() {
- pod := getPod(withCtr(getCtr(withImage(registry), withCmd([]string{"echo"}), withArg([]string{"hello"}))))
+ pod := getPod(withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd([]string{"echo"}), withArg([]string{"hello"}))))
err := generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -2507,7 +2507,7 @@ spec:
Expect(kube).To(ExitWithError())
})
- It("podman play kube test with read only HostPath volume", func() {
+ It("podman play kube test with read-only HostPath volume", func() {
hostPathLocation := filepath.Join(tempdir, "file")
f, err := os.Create(hostPathLocation)
Expect(err).To(BeNil())
@@ -3688,7 +3688,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
})
// Check the block devices are exposed inside container
- It("ddpodman play kube expose block device inside container", func() {
+ It("podman play kube expose block device inside container", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3705,7 +3705,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
blockVolume := getHostPathVolume("BlockDevice", devicePath)
- pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
+ pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
err = generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -3727,7 +3727,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
})
// Check the char devices are exposed inside container
- It("ddpodman play kube expose character device inside container", func() {
+ It("podman play kube expose character device inside container", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3744,7 +3744,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
charVolume := getHostPathVolume("CharDevice", devicePath)
- pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
+ pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
err = generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -3772,7 +3772,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
blockVolume := getHostPathVolume("BlockDevice", devicePath)
- pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
+ pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
err = generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -3781,7 +3781,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
Expect(kube).Should(Exit(125))
})
- It("ddpodman play kube reports error when we try to expose char device as block device", func() {
+ It("podman play kube reports error when we try to expose char device as block device", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3798,7 +3798,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
charVolume := getHostPathVolume("BlockDevice", devicePath)
- pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
+ pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
err = generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
@@ -3807,7 +3807,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
Expect(kube).Should(Exit(125))
})
- It("ddpodman play kube reports error when we try to expose block device as char device", func() {
+ It("podman play kube reports error when we try to expose block device as char device", func() {
SkipIfRootless("It needs root access to create devices")
// randomize the folder name to avoid error when running tests with multiple nodes
@@ -3823,7 +3823,7 @@ ENV OPENJ9_JAVA_OPTIONS=%q
charVolume := getHostPathVolume("CharDevice", devicePath)
- pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
+ pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(REGISTRY_IMAGE), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false))))
err = generateKubeYaml("pod", pod, kubeYaml)
Expect(err).To(BeNil())
diff --git a/test/e2e/pod_clone_test.go b/test/e2e/pod_clone_test.go
new file mode 100644
index 000000000..9c7abe7a8
--- /dev/null
+++ b/test/e2e/pod_clone_test.go
@@ -0,0 +1,194 @@
+package integration
+
+import (
+ "os"
+
+ . "github.com/containers/podman/v4/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+ . "github.com/onsi/gomega/gexec"
+)
+
+var _ = Describe("Podman pod clone", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ hostname, _ = os.Hostname()
+ )
+
+ BeforeEach(func() {
+ SkipIfRemote("podman pod clone is not supported in remote")
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ podmanTest.Setup()
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+
+ })
+
+ It("podman pod clone basic test", func() {
+ create := podmanTest.Podman([]string{"pod", "create", "--name", "1"})
+ create.WaitWithDefaultTimeout()
+ Expect(create).To(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "--pod", "1", "-dt", ALPINE})
+ run.WaitWithDefaultTimeout()
+ Expect(run).To(Exit(0))
+
+ clone := podmanTest.Podman([]string{"pod", "clone", create.OutputToString()})
+ clone.WaitWithDefaultTimeout()
+ Expect(clone).To(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).To(Exit(0))
+ data := podInspect.InspectPodToJSON()
+ Expect(data.Name).To(ContainSubstring("-clone"))
+
+ podStart := podmanTest.Podman([]string{"pod", "start", clone.OutputToString()})
+ podStart.WaitWithDefaultTimeout()
+ Expect(podStart).To(Exit(0))
+
+ podInspect = podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).To(Exit(0))
+ data = podInspect.InspectPodToJSON()
+ Expect(data.Containers[1].State).To(ContainSubstring("running")) // make sure non infra ctr is running
+ })
+
+ It("podman pod clone renaming test", func() {
+ create := podmanTest.Podman([]string{"pod", "create", "--name", "1"})
+ create.WaitWithDefaultTimeout()
+ Expect(create).To(Exit(0))
+
+ clone := podmanTest.Podman([]string{"pod", "clone", "--name", "2", create.OutputToString()})
+ clone.WaitWithDefaultTimeout()
+ Expect(clone).To(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).To(Exit(0))
+ data := podInspect.InspectPodToJSON()
+ Expect(data.Name).To(ContainSubstring("2"))
+
+ podStart := podmanTest.Podman([]string{"pod", "start", clone.OutputToString()})
+ podStart.WaitWithDefaultTimeout()
+ Expect(podStart).To(Exit(0))
+ })
+
+ It("podman pod clone start test", func() {
+ create := podmanTest.Podman([]string{"pod", "create", "--name", "1"})
+ create.WaitWithDefaultTimeout()
+ Expect(create).To(Exit(0))
+
+ clone := podmanTest.Podman([]string{"pod", "clone", "--start", create.OutputToString()})
+ clone.WaitWithDefaultTimeout()
+ Expect(clone).To(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", clone.OutputToString()})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).To(Exit(0))
+ data := podInspect.InspectPodToJSON()
+ Expect(data.State).To(ContainSubstring("Running"))
+
+ })
+
+ It("podman pod clone destroy test", func() {
+ create := podmanTest.Podman([]string{"pod", "create", "--name", "1"})
+ create.WaitWithDefaultTimeout()
+ Expect(create).To(Exit(0))
+
+ clone := podmanTest.Podman([]string{"pod", "clone", "--destroy", create.OutputToString()})
+ clone.WaitWithDefaultTimeout()
+ Expect(clone).To(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", create.OutputToString()})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).ToNot(Exit(0))
+ })
+
+ It("podman pod clone infra option test", func() {
+ // proof of concept that all currently tested infra options work since
+
+ volName := "testVol"
+ volCreate := podmanTest.Podman([]string{"volume", "create", volName})
+ volCreate.WaitWithDefaultTimeout()
+ Expect(volCreate).Should(Exit(0))
+
+ podName := "testPod"
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--name", podName})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ podClone := podmanTest.Podman([]string{"pod", "clone", "--volume", volName + ":/tmp1", podName})
+ podClone.WaitWithDefaultTimeout()
+ Expect(podClone).Should(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", "testPod-clone"})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).Should(Exit(0))
+ data := podInspect.InspectPodToJSON()
+ Expect(data.Mounts[0]).To(HaveField("Name", volName))
+ })
+
+ It("podman pod clone --shm-size", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ podClone := podmanTest.Podman([]string{"pod", "clone", "--shm-size", "10mb", podCreate.OutputToString()})
+ podClone.WaitWithDefaultTimeout()
+ Expect(podClone).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-it", "--pod", podClone.OutputToString(), ALPINE, "mount"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+ t, strings := run.GrepString("shm on /dev/shm type tmpfs")
+ Expect(t).To(BeTrue())
+ Expect(strings[0]).Should(ContainSubstring("size=10240k"))
+ })
+
+ It("podman pod clone --uts test", func() {
+ SkipIfRemote("hostname for the custom NS test is not as expected on the remote client")
+
+ session := podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"pod", "clone", "--uts", "host", session.OutputToString()})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "-it", "--pod", session.OutputToString(), ALPINE, "printenv", "HOSTNAME"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring(hostname))
+
+ podName := "utsPod"
+ ns := "ns:/proc/self/ns/"
+
+ session = podmanTest.Podman([]string{"pod", "create"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // just share uts with a custom path
+ podCreate := podmanTest.Podman([]string{"pod", "clone", "--uts", ns, "--name", podName, session.OutputToString()})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", podName})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).Should(Exit(0))
+ podJSON := podInspect.InspectPodToJSON()
+ Expect(podJSON.InfraConfig).To(HaveField("UtsNS", ns))
+ })
+
+})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index dedb1caeb..3caae2bd5 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -23,9 +23,10 @@ import (
var _ = Describe("Podman pod create", func() {
var (
- tempdir string
- err error
- podmanTest *PodmanTestIntegration
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ hostname, _ = os.Hostname()
)
BeforeEach(func() {
@@ -98,7 +99,7 @@ var _ = Describe("Podman pod create", func() {
Expect(session).Should(Exit(0))
pod := session.OutputToString()
- webserver := podmanTest.Podman([]string{"run", "--pod", pod, "-dt", nginx})
+ webserver := podmanTest.Podman([]string{"run", "--pod", pod, "-dt", NGINX_IMAGE})
webserver.WaitWithDefaultTimeout()
Expect(webserver).Should(Exit(0))
@@ -114,7 +115,7 @@ var _ = Describe("Podman pod create", func() {
Expect(session).Should(Exit(0))
pod := session.OutputToString()
- webserver := podmanTest.Podman([]string{"run", "--pod", pod, "-dt", nginx})
+ webserver := podmanTest.Podman([]string{"run", "--pod", pod, "-dt", NGINX_IMAGE})
webserver.WaitWithDefaultTimeout()
Expect(webserver).Should(Exit(0))
Expect(ncz(port)).To(BeTrue())
@@ -128,7 +129,7 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- webserver := podmanTest.Podman([]string{"run", "--pod-id-file", file, "-dt", nginx})
+ webserver := podmanTest.Podman([]string{"run", "--pod-id-file", file, "-dt", NGINX_IMAGE})
webserver.WaitWithDefaultTimeout()
Expect(webserver).Should(Exit(0))
Expect(ncz(port)).To(BeTrue())
@@ -899,27 +900,6 @@ ENTRYPOINT ["sleep","99999"]
})
- It("podman pod create --device-read-bps", func() {
- SkipIfRootless("Cannot create devices in /dev in rootless mode")
- SkipIfRootlessCgroupsV1("Setting device-read-bps not supported on cgroupv1 for rootless users")
-
- podName := "testPod"
- session := podmanTest.Podman([]string{"pod", "create", "--device-read-bps", "/dev/zero:1mb", "--name", podName})
- session.WaitWithDefaultTimeout()
- Expect(session).Should(Exit(0))
-
- if CGROUPSV2 {
- session = podmanTest.Podman([]string{"run", "--rm", "--pod", podName, ALPINE, "sh", "-c", "cat /sys/fs/cgroup/$(sed -e 's|0::||' < /proc/self/cgroup)/io.max"})
- } else {
- session = podmanTest.Podman([]string{"run", "--rm", "--pod", podName, ALPINE, "cat", "/sys/fs/cgroup/blkio/blkio.throttle.read_bps_device"})
- }
- session.WaitWithDefaultTimeout()
- Expect(session).Should(Exit(0))
- if !CGROUPSV2 {
- Expect(session.OutputToString()).To(ContainSubstring("1048576"))
- }
- })
-
It("podman pod create --volumes-from", func() {
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", volName})
@@ -1112,4 +1092,73 @@ ENTRYPOINT ["sleep","99999"]
})
+ It("podman pod create infra inheritance test", func() {
+ volName := "testVol1"
+ volCreate := podmanTest.Podman([]string{"volume", "create", volName})
+ volCreate.WaitWithDefaultTimeout()
+ Expect(volCreate).Should(Exit(0))
+
+ session := podmanTest.Podman([]string{"pod", "create", "-v", volName + ":/vol1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ volName2 := "testVol2"
+ volCreate = podmanTest.Podman([]string{"volume", "create", volName2})
+ volCreate.WaitWithDefaultTimeout()
+ Expect(volCreate).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", session.OutputToString(), "-v", volName2 + ":/vol2", ALPINE, "mount"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(ContainSubstring("/vol1"))
+ Expect(session.OutputToString()).Should(ContainSubstring("/vol2"))
+ })
+
+ It("podman pod create --shm-size", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--shm-size", "10mb"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-it", "--pod", podCreate.OutputToString(), ALPINE, "mount"})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+ t, strings := run.GrepString("shm on /dev/shm type tmpfs")
+ Expect(t).To(BeTrue())
+ Expect(strings[0]).Should(ContainSubstring("size=10240k"))
+ })
+
+ It("podman pod create --shm-size and --ipc=host conflict", func() {
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--shm-size", "10mb"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ run := podmanTest.Podman([]string{"run", "-dt", "--pod", podCreate.OutputToString(), "--ipc", "host", ALPINE})
+ run.WaitWithDefaultTimeout()
+ Expect(run).ShouldNot(Exit(0))
+ })
+
+ It("podman pod create --uts test", func() {
+ session := podmanTest.Podman([]string{"pod", "create", "--uts", "host"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "-it", "--pod", session.OutputToString(), ALPINE, "printenv", "HOSTNAME"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).To(ContainSubstring(hostname))
+
+ podName := "utsPod"
+ ns := "ns:/proc/self/ns/"
+
+ // just share uts with a custom path
+ podCreate := podmanTest.Podman([]string{"pod", "create", "--uts", ns, "--name", podName, "--share", "uts"})
+ podCreate.WaitWithDefaultTimeout()
+ Expect(podCreate).Should(Exit(0))
+
+ podInspect := podmanTest.Podman([]string{"pod", "inspect", podName})
+ podInspect.WaitWithDefaultTimeout()
+ Expect(podInspect).Should(Exit(0))
+ podJSON := podInspect.InspectPodToJSON()
+ Expect(podJSON.InfraConfig).To(HaveField("UtsNS", ns))
+ })
})
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index ab204992c..a2e090524 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -114,7 +114,7 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, nginx})
+ session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, NGINX_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -125,6 +125,29 @@ var _ = Describe("Podman pod create", func() {
session = podmanTest.Podman([]string{"run", fedoraMinimal, "curl", "-f", "localhost"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
+
+ session = podmanTest.Podman([]string{"pod", "create", "--network", "host"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--name", "hostCtr", "--pod", session.OutputToString(), ALPINE, "readlink", "/proc/self/ns/net"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ ns := SystemExec("readlink", []string{"/proc/self/ns/net"})
+ ns.WaitWithDefaultTimeout()
+ Expect(ns).Should(Exit(0))
+ netns := ns.OutputToString()
+ Expect(netns).ToNot(BeEmpty())
+
+ Expect(session.OutputToString()).To(Equal(netns))
+
+ // Sanity Check for podman inspect
+ session = podmanTest.Podman([]string{"inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "hostCtr"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToString()).Should(Equal("''")) // no network path... host
+
})
It("podman pod correctly sets up IPCNS", func() {
@@ -214,11 +237,11 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, nginx})
+ session = podmanTest.Podman([]string{"run", "-d", "--pod", podID, NGINX_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"run", "--pod", podID, "--network", "bridge", nginx, "curl", "-f", "localhost"})
+ session = podmanTest.Podman([]string{"run", "--pod", podID, "--network", "bridge", NGINX_IMAGE, "curl", "-f", "localhost"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
})
diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go
index d78890347..39e5696fa 100644
--- a/test/e2e/pod_pause_test.go
+++ b/test/e2e/pod_pause_test.go
@@ -56,7 +56,7 @@ var _ = Describe("Podman pod pause", func() {
Expect(result).Should(Exit(0))
})
- It("podman pod pause a running pod by id", func() {
+ It("pause a running pod by id", func() {
_, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
@@ -73,11 +73,10 @@ var _ = Describe("Podman pod pause", func() {
result = podmanTest.Podman([]string{"pod", "unpause", podid})
result.WaitWithDefaultTimeout()
-
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
})
- It("podman unpause a running pod by id", func() {
+ It("unpause a paused pod by id", func() {
_, ec, podid := podmanTest.CreatePod(nil)
Expect(ec).To(Equal(0))
@@ -85,14 +84,21 @@ var _ = Describe("Podman pod pause", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- result := podmanTest.Podman([]string{"pod", "unpause", podid})
+ result := podmanTest.Podman([]string{"pod", "pause", podid})
result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToStringArray()).Should(HaveLen(1))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
+ Expect(podmanTest.GetContainerStatus()).To(Equal(pausedState))
+ result = podmanTest.Podman([]string{"pod", "unpause", podid})
+ result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ Expect(result.OutputToStringArray()).Should(HaveLen(1))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
})
- It("podman pod pause a running pod by name", func() {
+ It("unpause a paused pod by name", func() {
_, ec, _ := podmanTest.CreatePod(map[string][]string{"--name": {"test1"}})
Expect(ec).To(Equal(0))
@@ -102,13 +108,42 @@ var _ = Describe("Podman pod pause", func() {
result := podmanTest.Podman([]string{"pod", "pause", "test1"})
result.WaitWithDefaultTimeout()
-
Expect(result).Should(Exit(0))
+ Expect(result.OutputToStringArray()).Should(HaveLen(1))
Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
Expect(podmanTest.GetContainerStatus()).To(Equal(pausedState))
result = podmanTest.Podman([]string{"pod", "unpause", "test1"})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
+ Expect(result.OutputToStringArray()).Should(HaveLen(1))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ })
+
+ It("unpause --all", func() {
+ _, ec, podid1 := podmanTest.CreatePod(nil)
+ Expect(ec).To(Equal(0))
+ _, ec, podid2 := podmanTest.CreatePod(nil)
+ Expect(ec).To(Equal(0))
+
+ session := podmanTest.RunTopContainerInPod("", podid1)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ session = podmanTest.RunTopContainerInPod("", podid2)
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ result := podmanTest.Podman([]string{"pod", "pause", podid1})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToStringArray()).Should(HaveLen(1))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
+ Expect(podmanTest.GetContainerStatus()).To(ContainSubstring(pausedState))
+
+ result = podmanTest.Podman([]string{"pod", "unpause", "--all"})
+ result.WaitWithDefaultTimeout()
+ Expect(result).Should(Exit(0))
+ Expect(result.OutputToStringArray()).Should(HaveLen(1))
+ Expect(podmanTest.NumberOfContainersRunning()).To(Equal(2))
})
})
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index 75adf1724..119c8d41e 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -258,6 +258,29 @@ var _ = Describe("Podman prune", func() {
Expect(pods.OutputToStringArray()).To(HaveLen(2))
})
+ It("podman system prune networks", func() {
+ // About netavark network backend test.
+ session := podmanTest.Podman([]string{"network", "create", "test"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"system", "prune", "-f"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // Default network should exists.
+ session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^podman$"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(HaveLen(1))
+
+ // Remove all unused networks.
+ session = podmanTest.Podman([]string{"network", "ls", "-q", "--filter", "name=^test$"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(HaveLen(0))
+ })
+
It("podman system prune - pod,container stopped", func() {
session := podmanTest.Podman([]string{"pod", "create"})
session.WaitWithDefaultTimeout()
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index 55e8d637b..04b7a280d 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -256,7 +256,7 @@ var _ = Describe("Podman pull", func() {
It("podman pull from docker-archive", func() {
SkipIfRemote("podman-remote does not support pulling from docker-archive")
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
tarfn := filepath.Join(podmanTest.TempDir, "cirros.tar")
session := podmanTest.Podman([]string{"save", "-o", tarfn, "cirros"})
session.WaitWithDefaultTimeout()
@@ -319,7 +319,7 @@ var _ = Describe("Podman pull", func() {
It("podman pull from oci-archive", func() {
SkipIfRemote("podman-remote does not support pulling from oci-archive")
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
tarfn := filepath.Join(podmanTest.TempDir, "oci-cirrus.tar")
session := podmanTest.Podman([]string{"save", "--format", "oci-archive", "-o", tarfn, "cirros"})
session.WaitWithDefaultTimeout()
@@ -339,7 +339,7 @@ var _ = Describe("Podman pull", func() {
It("podman pull from local directory", func() {
SkipIfRemote("podman-remote does not support pulling from local directory")
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
dirpath := filepath.Join(podmanTest.TempDir, "cirros")
err = os.MkdirAll(dirpath, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
@@ -363,7 +363,7 @@ var _ = Describe("Podman pull", func() {
It("podman pull from local OCI directory", func() {
SkipIfRemote("podman-remote does not support pulling from OCI directory")
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
dirpath := filepath.Join(podmanTest.TempDir, "cirros")
err = os.MkdirAll(dirpath, os.ModePerm)
Expect(err).ToNot(HaveOccurred())
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index 0288bf915..97567e40d 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -96,17 +96,16 @@ var _ = Describe("Podman push", func() {
})
It("podman push to local registry", func() {
- SkipIfRemote("Remote does not support --digestfile or --remove-signatures")
if podmanTest.Host.Arch == "ppc64le" {
Skip("No registry image for ppc64le")
}
if rootless.IsRootless() {
- err := podmanTest.RestoreArtifact(registry)
+ err := podmanTest.RestoreArtifact(REGISTRY_IMAGE)
Expect(err).ToNot(HaveOccurred())
}
lock := GetPortLock("5000")
defer lock.Unlock()
- session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
+ session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -118,6 +117,7 @@ var _ = Describe("Podman push", func() {
push.WaitWithDefaultTimeout()
Expect(push).Should(Exit(0))
+ SkipIfRemote("Remote does not support --digestfile")
// Test --digestfile option
push2 := podmanTest.Podman([]string{"push", "--tls-verify=false", "--digestfile=/tmp/digestfile.txt", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
push2.WaitWithDefaultTimeout()
@@ -156,7 +156,7 @@ var _ = Describe("Podman push", func() {
}
lock := GetPortLock("5000")
defer lock.Unlock()
- session := podmanTest.Podman([]string{"run", "--entrypoint", "htpasswd", registry, "-Bbn", "podmantest", "test"})
+ session := podmanTest.Podman([]string{"run", "--entrypoint", "htpasswd", REGISTRY_IMAGE, "-Bbn", "podmantest", "test"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -173,7 +173,7 @@ var _ = Describe("Podman push", func() {
strings.Join([]string{authPath, "/auth"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
"-v", strings.Join([]string{certPath, "/certs"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt",
- "-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", registry})
+ "-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index cc3cceda5..d1a0cd6f5 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -50,7 +50,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi with short name", func() {
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
session := podmanTest.Podman([]string{"rmi", "cirros"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -58,7 +58,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi all images", func() {
- podmanTest.AddImageToRWStore(nginx)
+ podmanTest.AddImageToRWStore(NGINX_IMAGE)
session := podmanTest.Podman([]string{"rmi", "-a"})
session.WaitWithDefaultTimeout()
images := podmanTest.Podman([]string{"images"})
@@ -68,7 +68,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi all images forcibly with short options", func() {
- podmanTest.AddImageToRWStore(nginx)
+ podmanTest.AddImageToRWStore(NGINX_IMAGE)
session := podmanTest.Podman([]string{"rmi", "-fa"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -76,12 +76,12 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi tagged image", func() {
- podmanTest.AddImageToRWStore(cirros)
- setup := podmanTest.Podman([]string{"images", "-q", cirros})
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
+ setup := podmanTest.Podman([]string{"images", "-q", CIRROS_IMAGE})
setup.WaitWithDefaultTimeout()
Expect(setup).Should(Exit(0))
- session := podmanTest.Podman([]string{"tag", cirros, "foo:bar", "foo"})
+ session := podmanTest.Podman([]string{"tag", CIRROS_IMAGE, "foo:bar", "foo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -93,8 +93,8 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi image with tags by ID cannot be done without force", func() {
- podmanTest.AddImageToRWStore(cirros)
- setup := podmanTest.Podman([]string{"images", "-q", cirros})
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
+ setup := podmanTest.Podman([]string{"images", "-q", CIRROS_IMAGE})
setup.WaitWithDefaultTimeout()
Expect(setup).Should(Exit(0))
cirrosID := setup.OutputToString()
@@ -116,8 +116,8 @@ var _ = Describe("Podman rmi", func() {
It("podman rmi image that is a parent of another image", func() {
Skip("I need help with this one. i don't understand what is going on")
- podmanTest.AddImageToRWStore(cirros)
- session := podmanTest.Podman([]string{"run", "--name", "c_test", cirros, "true"})
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
+ session := podmanTest.Podman([]string{"run", "--name", "c_test", CIRROS_IMAGE, "true"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -129,7 +129,7 @@ var _ = Describe("Podman rmi", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"rmi", cirros})
+ session = podmanTest.Podman([]string{"rmi", CIRROS_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -183,12 +183,12 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi with cached images", func() {
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
dockerfile := fmt.Sprintf(`FROM %s
RUN mkdir hello
RUN touch test.txt
ENV foo=bar
- `, cirros)
+ `, CIRROS_IMAGE)
podmanTest.BuildImage(dockerfile, "test", "true")
dockerfile = fmt.Sprintf(`FROM %s
@@ -196,7 +196,7 @@ var _ = Describe("Podman rmi", func() {
RUN touch test.txt
RUN mkdir blah
ENV foo=bar
- `, cirros)
+ `, CIRROS_IMAGE)
podmanTest.BuildImage(dockerfile, "test2", "true")
@@ -225,7 +225,7 @@ var _ = Describe("Podman rmi", func() {
podmanTest.BuildImage(dockerfile, "test3", "true")
- session = podmanTest.Podman([]string{"rmi", cirros})
+ session = podmanTest.Podman([]string{"rmi", CIRROS_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -250,7 +250,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi -a with parent|child images", func() {
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
dockerfile := fmt.Sprintf(`FROM %s AS base
RUN touch /1
ENV LOCAL=/1
@@ -258,7 +258,7 @@ RUN find $LOCAL
FROM base
RUN find $LOCAL
-`, cirros)
+`, CIRROS_IMAGE)
podmanTest.BuildImage(dockerfile, "test", "true")
session := podmanTest.Podman([]string{"rmi", "-a"})
session.WaitWithDefaultTimeout()
@@ -285,7 +285,7 @@ RUN find $LOCAL
// a race, we may not hit the condition a 100 percent of times
// but ocal reproducers hit it all the time.
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
var wg sync.WaitGroup
buildAndRemove := func(i int) {
@@ -293,7 +293,7 @@ RUN find $LOCAL
defer wg.Done()
imageName := fmt.Sprintf("rmtest:%d", i)
containerfile := fmt.Sprintf(`FROM %s
-RUN touch %s`, cirros, imageName)
+RUN touch %s`, CIRROS_IMAGE, imageName)
podmanTest.BuildImage(containerfile, imageName, "false")
session := podmanTest.Podman([]string{"rmi", "-f", imageName})
diff --git a/test/e2e/run_aardvark_test.go b/test/e2e/run_aardvark_test.go
index 25eb8b538..2c7dea9f4 100644
--- a/test/e2e/run_aardvark_test.go
+++ b/test/e2e/run_aardvark_test.go
@@ -42,7 +42,7 @@ var _ = Describe("Podman run networking", func() {
defer podmanTest.removeNetwork(netName)
Expect(session).Should(Exit(0))
- ctrID := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, nginx})
+ ctrID := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, NGINX_IMAGE})
ctrID.WaitWithDefaultTimeout()
Expect(ctrID).Should(Exit(0))
cid := ctrID.OutputToString()
@@ -53,7 +53,7 @@ var _ = Describe("Podman run networking", func() {
cip := ctrIP.OutputToString()
Expect(cip).To(MatchRegexp(IPRegex))
- digShort(cid, "aone", []string{cip}, podmanTest)
+ digShort(cid, "aone", cip, podmanTest)
reverseLookup := podmanTest.Podman([]string{"exec", cid, "dig", "+short", "-x", cip})
reverseLookup.WaitWithDefaultTimeout()
@@ -72,7 +72,7 @@ var _ = Describe("Podman run networking", func() {
defer podmanTest.removeNetwork(netName)
Expect(session).Should(Exit(0))
- ctr1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, nginx})
+ ctr1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, NGINX_IMAGE})
ctr1.WaitWithDefaultTimeout()
Expect(ctr1).Should(Exit(0))
cid1 := ctr1.OutputToString()
@@ -83,7 +83,7 @@ var _ = Describe("Podman run networking", func() {
cip1 := ctrIP1.OutputToString()
Expect(cip1).To(MatchRegexp(IPRegex))
- ctr2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwo", "--network", netName, nginx})
+ ctr2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwo", "--network", netName, NGINX_IMAGE})
ctr2.WaitWithDefaultTimeout()
Expect(ctr2).Should(Exit(0))
cid2 := ctr2.OutputToString()
@@ -94,9 +94,9 @@ var _ = Describe("Podman run networking", func() {
cip2 := ctrIP2.OutputToString()
Expect(cip2).To(MatchRegexp(IPRegex))
- digShort("aone", "atwo", []string{cip2}, podmanTest)
+ digShort("aone", "atwo", cip2, podmanTest)
- digShort("atwo", "aone", []string{cip1}, podmanTest)
+ digShort("atwo", "aone", cip1, podmanTest)
reverseLookup12 := podmanTest.Podman([]string{"exec", cid1, "dig", "+short", "-x", cip2})
reverseLookup12.WaitWithDefaultTimeout()
@@ -123,7 +123,7 @@ var _ = Describe("Podman run networking", func() {
defer podmanTest.removeNetwork(netName)
Expect(session).Should(Exit(0))
- ctr1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, "--network-alias", "alias_a1,alias_1a", nginx})
+ ctr1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netName, "--network-alias", "alias_a1,alias_1a", NGINX_IMAGE})
ctr1.WaitWithDefaultTimeout()
Expect(ctr1).Should(Exit(0))
@@ -133,7 +133,7 @@ var _ = Describe("Podman run networking", func() {
cip1 := ctrIP1.OutputToString()
Expect(cip1).To(MatchRegexp(IPRegex))
- ctr2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwo", "--network", netName, "--network-alias", "alias_a2,alias_2a", nginx})
+ ctr2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwo", "--network", netName, "--network-alias", "alias_a2,alias_2a", NGINX_IMAGE})
ctr2.WaitWithDefaultTimeout()
Expect(ctr2).Should(Exit(0))
@@ -143,17 +143,17 @@ var _ = Describe("Podman run networking", func() {
cip2 := ctrIP2.OutputToString()
Expect(cip2).To(MatchRegexp(IPRegex))
- digShort("aone", "atwo", []string{cip2}, podmanTest)
+ digShort("aone", "atwo", cip2, podmanTest)
- digShort("aone", "alias_a2", []string{cip2}, podmanTest)
+ digShort("aone", "alias_a2", cip2, podmanTest)
- digShort("aone", "alias_2a", []string{cip2}, podmanTest)
+ digShort("aone", "alias_2a", cip2, podmanTest)
- digShort("atwo", "aone", []string{cip1}, podmanTest)
+ digShort("atwo", "aone", cip1, podmanTest)
- digShort("atwo", "alias_a1", []string{cip1}, podmanTest)
+ digShort("atwo", "alias_a1", cip1, podmanTest)
- digShort("atwo", "alias_1a", []string{cip1}, podmanTest)
+ digShort("atwo", "alias_1a", cip1, podmanTest)
})
@@ -170,11 +170,11 @@ var _ = Describe("Podman run networking", func() {
defer podmanTest.removeNetwork(netNameB)
Expect(sessionB).Should(Exit(0))
- ctrA1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, nginx})
+ ctrA1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, NGINX_IMAGE})
ctrA1.WaitWithDefaultTimeout()
cidA1 := ctrA1.OutputToString()
- ctrB1 := podmanTest.Podman([]string{"run", "-dt", "--name", "bone", "--network", netNameB, nginx})
+ ctrB1 := podmanTest.Podman([]string{"run", "-dt", "--name", "bone", "--network", netNameB, NGINX_IMAGE})
ctrB1.WaitWithDefaultTimeout()
cidB1 := ctrB1.OutputToString()
@@ -214,7 +214,7 @@ var _ = Describe("Podman run networking", func() {
defer podmanTest.removeNetwork(netNameB)
Expect(sessionB).Should(Exit(0))
- ctrA1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, nginx})
+ ctrA1 := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, NGINX_IMAGE})
ctrA1.WaitWithDefaultTimeout()
cidA1 := ctrA1.OutputToString()
@@ -224,7 +224,7 @@ var _ = Describe("Podman run networking", func() {
cipA1 := ctrIPA1.OutputToString()
Expect(cipA1).To(MatchRegexp(IPRegex))
- ctrB1 := podmanTest.Podman([]string{"run", "-dt", "--name", "bone", "--network", netNameB, nginx})
+ ctrB1 := podmanTest.Podman([]string{"run", "-dt", "--name", "bone", "--network", netNameB, NGINX_IMAGE})
ctrB1.WaitWithDefaultTimeout()
cidB1 := ctrB1.OutputToString()
@@ -234,7 +234,7 @@ var _ = Describe("Podman run networking", func() {
cipB1 := ctrIPB1.OutputToString()
Expect(cipB1).To(MatchRegexp(IPRegex))
- ctrA2B2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwobtwo", "--network", netNameA, "--network", netNameB, nginx})
+ ctrA2B2 := podmanTest.Podman([]string{"run", "-dt", "--name", "atwobtwo", "--network", netNameA, "--network", netNameB, NGINX_IMAGE})
ctrA2B2.WaitWithDefaultTimeout()
cidA2B2 := ctrA2B2.OutputToString()
@@ -250,13 +250,13 @@ var _ = Describe("Podman run networking", func() {
cipA2B22 := ctrIPA2B22.OutputToString()
Expect(cipA2B22).To(MatchRegexp(IPRegex))
- digShort("aone", "atwobtwo", []string{cipA2B21}, podmanTest)
+ digShort("aone", "atwobtwo", cipA2B21, podmanTest)
- digShort("bone", "atwobtwo", []string{cipA2B22}, podmanTest)
+ digShort("bone", "atwobtwo", cipA2B22, podmanTest)
- digShort("atwobtwo", "aone", []string{cipA1}, podmanTest)
+ digShort("atwobtwo", "aone", cipA1, podmanTest)
- digShort("atwobtwo", "bone", []string{cipB1}, podmanTest)
+ digShort("atwobtwo", "bone", cipB1, podmanTest)
})
It("Aardvark Test 6: Three subnets, first container on 1/2 and second on 2/3, w/ network aliases", func() {
@@ -278,11 +278,11 @@ var _ = Describe("Podman run networking", func() {
defer podmanTest.removeNetwork(netNameC)
Expect(sessionC).Should(Exit(0))
- ctrA := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, nginx})
+ ctrA := podmanTest.Podman([]string{"run", "-dt", "--name", "aone", "--network", netNameA, NGINX_IMAGE})
ctrA.WaitWithDefaultTimeout()
Expect(ctrA).Should(Exit(0))
- ctrC := podmanTest.Podman([]string{"run", "-dt", "--name", "cone", "--network", netNameC, nginx})
+ ctrC := podmanTest.Podman([]string{"run", "-dt", "--name", "cone", "--network", netNameC, NGINX_IMAGE})
ctrC.WaitWithDefaultTimeout()
Expect(ctrC).Should(Exit(0))
@@ -304,10 +304,9 @@ var _ = Describe("Podman run networking", func() {
Expect(ctrIPCB2).Should(Exit(0))
cipCB2 := ctrIPCB2.OutputToString()
- digShort("aone", "testB2_nw", []string{cipCB2}, podmanTest)
-
- digShort("cone", "testB1_nw", []string{cipAB1}, podmanTest)
+ digShort("aone", "testB2_nw", cipCB2, podmanTest)
+ digShort("cone", "testB1_nw", cipAB1, podmanTest)
})
})
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 3b32b4b82..1ad78c950 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -381,7 +381,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
session := podmanTest.Podman([]string{"run", "-dt", "-p", fmt.Sprintf("%d:%d", port1, port2), ALPINE, "/bin/sh"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- results := SystemExec("iptables", []string{"-t", "nat", "-L"})
+ results := SystemExec("iptables", []string{"-t", "nat", "-nvL"})
Expect(results).Should(Exit(0))
Expect(results.OutputToString()).To(ContainSubstring(fmt.Sprintf("%d", port2)))
@@ -513,7 +513,7 @@ EXPOSE 2004-2005/tcp`, ALPINE)
})
It("podman run network expose ports in image metadata", func() {
- session := podmanTest.Podman([]string{"create", "--name", "test", "-t", "-P", nginx})
+ session := podmanTest.Podman([]string{"create", "--name", "test", "-t", "-P", NGINX_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
results := podmanTest.Podman([]string{"inspect", "test"})
diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go
index 4f0b512c6..dfaff7e67 100644
--- a/test/e2e/run_privileged_test.go
+++ b/test/e2e/run_privileged_test.go
@@ -131,6 +131,30 @@ var _ = Describe("Podman privileged container tests", func() {
Expect(len(session.OutputToStringArray())).To(BeNumerically(">", 20))
})
+ It("podman privileged should restart after host devices change", func() {
+ containerName := "privileged-restart-test"
+ SkipIfRootless("Cannot create devices in /dev in rootless mode")
+ Expect(os.MkdirAll("/dev/foodevdir", os.ModePerm)).To(BeNil())
+
+ mknod := SystemExec("mknod", []string{"/dev/foodevdir/null", "c", "1", "3"})
+ mknod.WaitWithDefaultTimeout()
+ Expect(mknod).Should(Exit(0))
+
+ session := podmanTest.Podman([]string{"run", "--name=" + containerName, "--privileged", "-it", fedoraMinimal, "ls", "/dev"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ deviceFiles := session.OutputToStringArray()
+
+ os.RemoveAll("/dev/foodevdir")
+ session = podmanTest.Podman([]string{"start", "--attach", containerName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ deviceFilesAfterRemoval := session.OutputToStringArray()
+ Expect(deviceFiles).To(Not(Equal(deviceFilesAfterRemoval)))
+ })
+
It("run no-new-privileges test", func() {
// Check if our kernel is new enough
k, err := IsKernelNewerThan("4.14")
diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go
index af3f98d4b..8207f6d0b 100644
--- a/test/e2e/run_staticip_test.go
+++ b/test/e2e/run_staticip_test.go
@@ -28,7 +28,7 @@ var _ = Describe("Podman run with --ip flag", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
- // Cleanup the CNI networks used by the tests
+ // Clean up the CNI networks used by the tests
os.RemoveAll("/var/lib/cni/networks/podman")
})
@@ -101,7 +101,7 @@ 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", "--name", "nginx", "--ip", ip, nginx})
+ result := podmanTest.Podman([]string{"run", "-d", "--name", "nginx", "--ip", ip, NGINX_IMAGE})
result.WaitWithDefaultTimeout()
Expect(result).Should(Exit(0))
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 828e92170..6edb705a1 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -73,8 +73,30 @@ var _ = Describe("Podman run", func() {
Expect(session.OutputToString()).To(ContainSubstring("graphRootMounted=1"))
})
+ It("podman run from manifest list", func() {
+ session := podmanTest.Podman([]string{"manifest", "create", "localhost/test:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"build", "-f", "build/Containerfile.with-platform", "--platform", "linux/amd64,linux/arm64", "--manifest", "localhost/test:latest"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--platform", "linux/arm64", "localhost/test", "uname", "-a"})
+ session.WaitWithDefaultTimeout()
+ exitCode := session.ExitCode()
+ // CI could either support requested platform or not, if it supports then output should contain `aarch64`
+ // if not run should fail with a very specific error i.e `Exec format error` anything other than this should
+ // be marked as failure of test.
+ if exitCode == 0 {
+ Expect(session.OutputToString()).To(ContainSubstring("aarch64"))
+ } else {
+ Expect(session.ErrorToString()).To(ContainSubstring("Exec format error"))
+ }
+ })
+
It("podman run a container based on a complex local image name", func() {
- imageName := strings.TrimPrefix(nginx, "quay.io/")
+ imageName := strings.TrimPrefix(NGINX_IMAGE, "quay.io/")
session := podmanTest.Podman([]string{"run", imageName, "ls"})
session.WaitWithDefaultTimeout()
Expect(session.ErrorToString()).ToNot(ContainSubstring("Trying to pull"))
@@ -119,10 +141,10 @@ var _ = Describe("Podman run", func() {
})
It("podman run a container based on on a short name with localhost", func() {
- tag := podmanTest.Podman([]string{"tag", nginx, "localhost/libpod/alpine_nginx:latest"})
+ tag := podmanTest.Podman([]string{"tag", NGINX_IMAGE, "localhost/libpod/alpine_nginx:latest"})
tag.WaitWithDefaultTimeout()
- rmi := podmanTest.Podman([]string{"rmi", nginx})
+ rmi := podmanTest.Podman([]string{"rmi", NGINX_IMAGE})
rmi.WaitWithDefaultTimeout()
session := podmanTest.Podman([]string{"run", "libpod/alpine_nginx:latest", "ls"})
@@ -132,10 +154,10 @@ var _ = Describe("Podman run", func() {
})
It("podman container run a container based on on a short name with localhost", func() {
- tag := podmanTest.Podman([]string{"image", "tag", nginx, "localhost/libpod/alpine_nginx:latest"})
+ tag := podmanTest.Podman([]string{"image", "tag", NGINX_IMAGE, "localhost/libpod/alpine_nginx:latest"})
tag.WaitWithDefaultTimeout()
- rmi := podmanTest.Podman([]string{"image", "rm", nginx})
+ rmi := podmanTest.Podman([]string{"image", "rm", NGINX_IMAGE})
rmi.WaitWithDefaultTimeout()
session := podmanTest.Podman([]string{"container", "run", "libpod/alpine_nginx:latest", "ls"})
@@ -176,7 +198,7 @@ var _ = Describe("Podman run", func() {
lock := GetPortLock("5000")
defer lock.Unlock()
- session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
+ session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -1019,7 +1041,7 @@ echo -n %s >%s
})
It("podman run with built-in volume image", func() {
- session := podmanTest.Podman([]string{"run", "--rm", redis, "ls"})
+ session := podmanTest.Podman([]string{"run", "--rm", REDIS_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -1084,7 +1106,7 @@ USER mail`, BB)
Expect(session).Should(Exit(0))
ctrID := session.OutputToString()
- // check that the read only option works
+ // check that the read-only option works
session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID + ":ro", ALPINE, "touch", mountpoint + "abc.txt"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1))
@@ -1108,13 +1130,13 @@ USER mail`, BB)
Expect(session).Should(Exit(125))
Expect(session.ErrorToString()).To(ContainSubstring("cannot set :z more than once in mount options"))
- // create new read only volume
+ // create new read-only volume
session = podmanTest.Podman([]string{"create", "--volume", vol + ":" + mountpoint + ":ro", ALPINE, "cat", mountpoint + filename})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
ctrID = session.OutputToString()
- // check if the original volume was mounted as read only that --volumes-from also mount it as read only
+ // check if the original volume was mounted as read-only that --volumes-from also mount it as read-only
session = podmanTest.Podman([]string{"run", "--volumes-from", ctrID, ALPINE, "touch", mountpoint + "abc.txt"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(1))
@@ -1122,7 +1144,7 @@ USER mail`, BB)
})
It("podman run --volumes-from flag with built-in volumes", func() {
- session := podmanTest.Podman([]string{"create", redis, "sh"})
+ session := podmanTest.Podman([]string{"create", REDIS_IMAGE, "sh"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
ctrID := session.OutputToString()
@@ -1637,7 +1659,7 @@ USER mail`, BB)
session = podmanTest.Podman([]string{"run", "--umask", "9999", "--rm", ALPINE, "sh", "-c", "umask"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
- Expect(session.ErrorToString()).To(ContainSubstring("Invalid umask"))
+ Expect(session.ErrorToString()).To(ContainSubstring("invalid umask"))
})
It("podman run makes workdir from image", func() {
@@ -1679,24 +1701,24 @@ WORKDIR /madethis`, BB)
})
It("podman run container with --pull missing and only pull once", func() {
- session := podmanTest.Podman([]string{"run", "--pull", "missing", cirros, "ls"})
+ session := podmanTest.Podman([]string{"run", "--pull", "missing", CIRROS_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.ErrorToString()).To(ContainSubstring("Trying to pull"))
- session = podmanTest.Podman([]string{"run", "--pull", "missing", cirros, "ls"})
+ session = podmanTest.Podman([]string{"run", "--pull", "missing", CIRROS_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.ErrorToString()).ToNot(ContainSubstring("Trying to pull"))
})
It("podman run container with --pull missing should pull image multiple times", func() {
- session := podmanTest.Podman([]string{"run", "--pull", "always", cirros, "ls"})
+ session := podmanTest.Podman([]string{"run", "--pull", "always", CIRROS_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.ErrorToString()).To(ContainSubstring("Trying to pull"))
- session = podmanTest.Podman([]string{"run", "--pull", "always", cirros, "ls"})
+ session = podmanTest.Podman([]string{"run", "--pull", "always", CIRROS_IMAGE, "ls"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.ErrorToString()).To(ContainSubstring("Trying to pull"))
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 3bef889b7..aa8f49176 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -150,7 +150,7 @@ var _ = Describe("Podman run with volumes", func() {
})
It("podman run with conflict between image volume and user mount succeeds", func() {
- err = podmanTest.RestoreArtifact(redis)
+ err = podmanTest.RestoreArtifact(REDIS_IMAGE)
Expect(err).ToNot(HaveOccurred())
mountPath := filepath.Join(podmanTest.TempDir, "secrets")
err := os.Mkdir(mountPath, 0755)
@@ -160,7 +160,7 @@ var _ = Describe("Podman run with volumes", func() {
Expect(err).To(BeNil(), "os.Create(testfile)")
f.Close()
Expect(err).To(BeNil())
- session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data", mountPath), redis, "ls", "/data/test1"})
+ session := podmanTest.Podman([]string{"run", "-v", fmt.Sprintf("%s:/data", mountPath), REDIS_IMAGE, "ls", "/data/test1"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
@@ -325,6 +325,51 @@ var _ = Describe("Podman run with volumes", func() {
})
+ It("podman support overlay volume with custom upperdir and workdir", func() {
+ SkipIfRemote("Overlay volumes only work locally")
+ if os.Getenv("container") != "" {
+ Skip("Overlay mounts not supported when running in a container")
+ }
+ if rootless.IsRootless() {
+ if _, err := exec.LookPath("fuse-overlayfs"); err != nil {
+ Skip("Fuse-Overlayfs required for rootless overlay mount test")
+ }
+ }
+
+ // Use bindsource instead of named volume
+ bindSource := filepath.Join(tempdir, "bindsource")
+ err := os.Mkdir(bindSource, 0755)
+ Expect(err).To(BeNil(), "mkdir "+bindSource)
+
+ // create persistent upperdir on host
+ upperDir := filepath.Join(tempdir, "upper")
+ err = os.Mkdir(upperDir, 0755)
+ Expect(err).To(BeNil(), "mkdir "+upperDir)
+
+ // create persistent workdir on host
+ workDir := filepath.Join(tempdir, "work")
+ err = os.Mkdir(workDir, 0755)
+ Expect(err).To(BeNil(), "mkdir "+workDir)
+
+ overlayOpts := fmt.Sprintf("upperdir=%s,workdir=%s", upperDir, workDir)
+
+ // create file on overlay volume
+ session := podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "echo hello >> " + "/data/overlay"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O," + overlayOpts, ALPINE, "sh", "-c", "ls /data"})
+ session.WaitWithDefaultTimeout()
+ // must contain `overlay` file since it should be persistent on specified upper and workdir
+ Expect(session.OutputToString()).To(ContainSubstring("overlay"))
+
+ session = podmanTest.Podman([]string{"run", "--volume", bindSource + ":/data:O", ALPINE, "sh", "-c", "ls /data"})
+ session.WaitWithDefaultTimeout()
+ // must not contain `overlay` file which was on custom upper and workdir since we have not specified any upper or workdir
+ Expect(session.OutputToString()).To(Not(ContainSubstring("overlay")))
+
+ })
+
It("podman run with noexec can't exec", func() {
session := podmanTest.Podman([]string{"run", "--rm", "-v", "/bin:/hostbin:noexec", ALPINE, "/hostbin/ls", "/"})
session.WaitWithDefaultTimeout()
@@ -407,6 +452,14 @@ var _ = Describe("Podman run with volumes", func() {
separateVolumeSession.WaitWithDefaultTimeout()
Expect(separateVolumeSession).Should(Exit(0))
Expect(separateVolumeSession.OutputToString()).To(Equal(baselineOutput))
+
+ copySession := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol3:/etc/apk:copy", ALPINE, "stat", "-c", "%h", "/etc/apk/arch"})
+ copySession.WaitWithDefaultTimeout()
+ Expect(copySession).Should(Exit(0))
+
+ noCopySession := podmanTest.Podman([]string{"run", "--rm", "-v", "testvol4:/etc/apk:nocopy", ALPINE, "stat", "-c", "%h", "/etc/apk/arch"})
+ noCopySession.WaitWithDefaultTimeout()
+ Expect(noCopySession).Should(Exit(1))
})
It("podman named volume copyup symlink", func() {
@@ -539,7 +592,7 @@ RUN sh -c "cd /etc/apk && ln -s ../../testfile"`, ALPINE)
})
It("podman run image volume is not noexec", func() {
- session := podmanTest.Podman([]string{"run", "--rm", redis, "grep", "/data", "/proc/self/mountinfo"})
+ session := podmanTest.Podman([]string{"run", "--rm", REDIS_IMAGE, "grep", "/data", "/proc/self/mountinfo"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
Expect(session.OutputToString()).To(Not(ContainSubstring("noexec")))
@@ -625,6 +678,15 @@ VOLUME /test/`, ALPINE)
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
+ // Test overlay mount when lowerdir is relative path.
+ f, err = os.Create("hello")
+ Expect(err).To(BeNil(), "os.Create")
+ f.Close()
+ session = podmanTest.Podman([]string{"run", "--rm", "-v", ".:/app:O", ALPINE, "ls", "/app"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.OutputToString()).To(ContainSubstring("hello"))
+ Expect(session).Should(Exit(0))
+
// Make sure modifications in container do not show up on host
session = podmanTest.Podman([]string{"run", "--rm", "-v", volumeFlag, ALPINE, "touch", "/run/test/container"})
session.WaitWithDefaultTimeout()
@@ -863,6 +925,20 @@ USER testuser`, fedoraMinimal)
Expect(session.OutputToString()).To(Equal(perms))
})
+ It("podman run with -v $SRC:/run does not create /run/.containerenv", func() {
+ mountSrc := filepath.Join(podmanTest.TempDir, "vol-test1")
+ err := os.MkdirAll(mountSrc, 0755)
+ Expect(err).To(BeNil())
+
+ session := podmanTest.Podman([]string{"run", "-v", mountSrc + ":/run", ALPINE, "true"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ // the file should not have been created
+ _, err = os.Stat(filepath.Join(mountSrc, ".containerenv"))
+ Expect(err).To(Not(BeNil()))
+ })
+
It("podman volume with uid and gid works", func() {
volName := "testVol"
volCreate := podmanTest.Podman([]string{"volume", "create", "--opt", "o=uid=1000", volName})
@@ -894,4 +970,32 @@ USER testuser`, fedoraMinimal)
Expect(volMount).Should(Exit(0))
Expect(volMount.OutputToString()).To(Equal("1000:1000"))
})
+
+ It("podman run -v with a relative dir", func() {
+ mountPath := filepath.Join(podmanTest.TempDir, "vol")
+ err = os.Mkdir(mountPath, 0755)
+ Expect(err).ToNot(HaveOccurred())
+ defer func() {
+ err := os.RemoveAll(mountPath)
+ Expect(err).ToNot(HaveOccurred())
+ }()
+
+ f, err := os.CreateTemp(mountPath, "podman")
+ Expect(err).ToNot(HaveOccurred())
+
+ cwd, err := os.Getwd()
+ Expect(err).ToNot(HaveOccurred())
+
+ err = os.Chdir(mountPath)
+ Expect(err).ToNot(HaveOccurred())
+ defer func() {
+ err := os.Chdir(cwd)
+ Expect(err).ToNot(HaveOccurred())
+ }()
+
+ run := podmanTest.Podman([]string{"run", "-it", "--security-opt", "label=disable", "-v", "./:" + dest, ALPINE, "ls", dest})
+ run.WaitWithDefaultTimeout()
+ Expect(run).Should(Exit(0))
+ Expect(run.OutputToString()).Should(ContainSubstring(strings.TrimLeft("/vol/", f.Name())))
+ })
})
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index 897e49ef7..94c363dd4 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -153,7 +153,7 @@ var _ = Describe("Podman save", func() {
defer os.Setenv("GNUPGHOME", origGNUPGHOME)
port := 5000
- session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), "quay.io/libpod/registry:2.6"})
+ session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), REGISTRY_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
@@ -226,13 +226,17 @@ default-docker:
})
It("podman save --multi-image-archive (untagged images)", func() {
- // Refer to images via ID instead of tag.
- session := podmanTest.Podman([]string{"images", "--format", "{{.ID}}"})
+ // #14468: to make execution time more predictable, save at
+ // most three images and sort them by size.
+ session := podmanTest.Podman([]string{"images", "--sort", "size", "--format", "{{.ID}}"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
ids := session.OutputToStringArray()
Expect(len(ids)).To(BeNumerically(">", 1), "We need to have *some* images to save")
+ if len(ids) > 3 {
+ ids = ids[:3]
+ }
multiImageSave(podmanTest, ids)
})
})
diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go
index 64677ba54..f8b1bc836 100644
--- a/test/e2e/search_test.go
+++ b/test/e2e/search_test.go
@@ -206,7 +206,7 @@ registries = ['{{.Host}}:{{.Port}}']`
port := GetPort()
fakereg := podmanTest.Podman([]string{"run", "-d", "--name", "registry",
"-p", fmt.Sprintf("%d:5000", port),
- registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
+ REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
fakereg.WaitWithDefaultTimeout()
Expect(fakereg).Should(Exit(0))
@@ -231,7 +231,7 @@ registries = ['{{.Host}}:{{.Port}}']`
}
port := GetPort()
registry := podmanTest.Podman([]string{"run", "-d", "--name", "registry3",
- "-p", fmt.Sprintf("%d:5000", port), registry,
+ "-p", fmt.Sprintf("%d:5000", port), REGISTRY_IMAGE,
"/entrypoint.sh", "/etc/docker/registry/config.yml"})
registry.WaitWithDefaultTimeout()
Expect(registry).Should(Exit(0))
@@ -268,7 +268,7 @@ registries = ['{{.Host}}:{{.Port}}']`
port := GetPort()
ep := endpoint{Port: fmt.Sprintf("%d", port), Host: "localhost"}
registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port),
- "--name", "registry4", registry, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
+ "--name", "registry4", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
registry.WaitWithDefaultTimeout()
Expect(registry).Should(Exit(0))
@@ -313,7 +313,7 @@ registries = ['{{.Host}}:{{.Port}}']`
port := GetPort()
ep := endpoint{Port: fmt.Sprintf("%d", port), Host: "localhost"}
registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port),
- "--name", "registry5", registry})
+ "--name", "registry5", REGISTRY_IMAGE})
registry.WaitWithDefaultTimeout()
Expect(registry).Should(Exit(0))
@@ -353,7 +353,7 @@ registries = ['{{.Host}}:{{.Port}}']`
port := GetPort()
ep := endpoint{Port: fmt.Sprintf("%d", port), Host: "localhost"}
registry := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port),
- "--name", "registry6", registry})
+ "--name", "registry6", REGISTRY_IMAGE})
registry.WaitWithDefaultTimeout()
Expect(registry).Should(Exit(0))
@@ -401,7 +401,7 @@ registries = ['{{.Host}}:{{.Port}}']`
ep3 := endpoint{Port: fmt.Sprintf("%d", port3), Host: "localhost"}
registryLocal := podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d", port1),
- "--name", "registry7", registry})
+ "--name", "registry7", REGISTRY_IMAGE})
registryLocal.WaitWithDefaultTimeout()
Expect(registryLocal).Should(Exit(0))
@@ -409,7 +409,7 @@ registries = ['{{.Host}}:{{.Port}}']`
Fail("Cannot start docker registry on port %s", port1)
}
- registryLocal = podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port2), "--name", "registry8", registry})
+ registryLocal = podmanTest.Podman([]string{"run", "-d", "-p", fmt.Sprintf("%d:5000", port2), "--name", "registry8", REGISTRY_IMAGE})
registryLocal.WaitWithDefaultTimeout()
Expect(registryLocal).Should(Exit(0))
@@ -455,7 +455,6 @@ registries = ['{{.Host}}:{{.Port}}']`
})
It("podman search with wildcards", func() {
- Skip("FIXME: search on registry.redhat.io is broken (Dec 16 '21)")
search := podmanTest.Podman([]string{"search", "registry.redhat.io/*openshift*"})
search.WaitWithDefaultTimeout()
Expect(search).Should(Exit(0))
diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go
index b43a81cd3..3000a819f 100644
--- a/test/e2e/stats_test.go
+++ b/test/e2e/stats_test.go
@@ -236,4 +236,15 @@ var _ = Describe("Podman stats", func() {
Expect(customLimit).To(BeNumerically("<", defaultLimit))
})
+
+ It("podman stats with a container that is not running", func() {
+ ctr := "created_container"
+ session := podmanTest.Podman([]string{"create", "--name", ctr, ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"stats", "--no-stream", ctr})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ })
})
diff --git a/test/e2e/system_connection_test.go b/test/e2e/system_connection_test.go
index 2228c23b2..baa31424b 100644
--- a/test/e2e/system_connection_test.go
+++ b/test/e2e/system_connection_test.go
@@ -47,9 +47,7 @@ var _ = Describe("podman system connection", func() {
}
f := CurrentGinkgoTestDescription()
- _, _ = GinkgoWriter.Write(
- []byte(
- fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds())))
+ processTestResult(f)
})
Context("without running API service", func() {
@@ -58,7 +56,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
@@ -67,10 +65,10 @@ var _ = Describe("podman system connection", func() {
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
- Expect(cfg).To(HaveActiveService("QA"))
+ Expect(cfg).Should(HaveActiveService("QA"))
Expect(cfg).Should(VerifyService(
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
"~/.ssh/id_rsa",
))
@@ -82,7 +80,7 @@ var _ = Describe("podman system connection", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- Expect(config.ReadCustomConfig()).To(HaveActiveService("QE"))
+ Expect(config.ReadCustomConfig()).Should(HaveActiveService("QE"))
})
It("add UDS", func() {
@@ -141,7 +139,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -155,8 +153,8 @@ var _ = Describe("podman system connection", func() {
cfg, err := config.ReadCustomConfig()
Expect(err).ShouldNot(HaveOccurred())
- Expect(cfg.Engine.ActiveService).To(BeEmpty())
- Expect(cfg.Engine.ServiceDestinations).To(BeEmpty())
+ Expect(cfg.Engine.ActiveService).Should(BeEmpty())
+ Expect(cfg.Engine.ServiceDestinations).Should(BeEmpty())
}
})
@@ -165,7 +163,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
"QA",
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -187,7 +185,7 @@ var _ = Describe("podman system connection", func() {
"--default",
"--identity", "~/.ssh/id_rsa",
name,
- "ssh://root@server.fubar.com:2222/run/podman/podman.sock",
+ "ssh://root@podman.test:2222/run/podman/podman.sock",
}
session := podmanTest.Podman(cmd)
session.WaitWithDefaultTimeout()
@@ -247,7 +245,7 @@ var _ = Describe("podman system connection", func() {
// podman-remote commands will be executed by ginkgo directly.
SkipIfContainerized("sshd is not available when running in a container")
SkipIfRemote("connection heuristic requires both podman and podman-remote binaries")
- SkipIfNotRootless(fmt.Sprintf("FIXME: setup ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid()))
+ SkipIfNotRootless(fmt.Sprintf("FIXME: set up ssh keys when root. uid(%d) euid(%d)", os.Getuid(), os.Geteuid()))
SkipIfSystemdNotRunning("cannot test connection heuristic if systemd is not running")
SkipIfNotActive("sshd", "cannot test connection heuristic if sshd is not running")
})
diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go
index 5a23fc0bb..998fa8b59 100644
--- a/test/e2e/system_df_test.go
+++ b/test/e2e/system_df_test.go
@@ -70,6 +70,17 @@ var _ = Describe("podman system df", func() {
Expect(containers[1]).To(Equal("2"), "total containers expected")
Expect(volumes[2]).To(Equal("2"), "total volumes expected")
Expect(volumes[6]).To(Equal("(50%)"), "percentage usage expected")
+
+ session = podmanTest.Podman([]string{"rm", "container1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ session = podmanTest.Podman([]string{"system", "df"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ volumes = strings.Fields(session.OutputToStringArray()[3])
+ // percentages on volumes were being calculated incorrectly. Make sure we only report 100% and not above
+ Expect(volumes[6]).To(Equal("(100%)"), "percentage usage expected")
+
})
It("podman system df image with no tag", func() {
@@ -86,4 +97,17 @@ var _ = Describe("podman system df", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
})
+
+ It("podman system df --format \"{{ json . }}\"", func() {
+ session := podmanTest.Podman([]string{"create", ALPINE})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"system", "df", "--format", "{{ json . }}"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.LineInOutputContains("Size"))
+ Expect(session.LineInOutputContains("Reclaimable"))
+ Expect(session.IsJSONOutputValid())
+ })
})
diff --git a/test/e2e/system_reset_test.go b/test/e2e/system_reset_test.go
index 28f2e25ca..075ea435c 100644
--- a/test/e2e/system_reset_test.go
+++ b/test/e2e/system_reset_test.go
@@ -4,6 +4,7 @@ import (
"fmt"
"os"
+ "github.com/containers/podman/v4/pkg/rootless"
. "github.com/containers/podman/v4/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -92,9 +93,12 @@ var _ = Describe("podman system reset", func() {
// TODO: machine tests currently don't run outside of the machine test pkg
// no machines are created here to cleanup
- session = podmanTest.Podman([]string{"machine", "list", "-q"})
- session.WaitWithDefaultTimeout()
- Expect(session).Should(Exit(0))
- Expect(session.OutputToStringArray()).To(BeEmpty())
+ // machine commands are rootless only
+ if rootless.IsRootless() {
+ session = podmanTest.Podman([]string{"machine", "list", "-q"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(BeEmpty())
+ }
})
})
diff --git a/test/e2e/systemd_activate_test.go b/test/e2e/systemd_activate_test.go
index aeea4f932..240139b98 100644
--- a/test/e2e/systemd_activate_test.go
+++ b/test/e2e/systemd_activate_test.go
@@ -4,9 +4,11 @@ import (
"errors"
"fmt"
"io/fs"
+ "net"
"os"
"os/exec"
"path/filepath"
+ "strconv"
"syscall"
"time"
@@ -21,6 +23,7 @@ var _ = Describe("Systemd activate", func() {
var tempDir string
var err error
var podmanTest *PodmanTestIntegration
+ var activate string
BeforeEach(func() {
tempDir, err = testUtils.CreateTempDirInTempDir()
@@ -31,17 +34,10 @@ var _ = Describe("Systemd activate", func() {
podmanTest = PodmanTestCreate(tempDir)
podmanTest.Setup()
- })
- AfterEach(func() {
- podmanTest.Cleanup()
- processTestResult(CurrentGinkgoTestDescription())
- })
-
- It("stop podman.service", func() {
SkipIfRemote("Testing stopped service requires both podman and podman-remote binaries")
- activate, err := exec.LookPath("systemd-socket-activate")
+ activate, err = exec.LookPath("systemd-socket-activate")
if err != nil {
activate = "/usr/bin/systemd-socket-activate"
}
@@ -54,14 +50,22 @@ var _ = Describe("Systemd activate", func() {
case err != nil:
Skip(err.Error())
}
+ })
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ processTestResult(CurrentGinkgoTestDescription())
+ })
+
+ It("stop podman.service", func() {
// systemd-socket-activate does not support DNS lookups
host := "127.0.0.1"
port, err := podmanUtils.GetRandomPort()
Expect(err).ToNot(HaveOccurred())
+ addr := net.JoinHostPort(host, strconv.Itoa(port))
activateSession := testUtils.StartSystemExec(activate, []string{
- fmt.Sprintf("--listen=%s:%d", host, port),
+ "--listen", addr,
podmanTest.PodmanBinary,
"--root=" + filepath.Join(tempDir, "server_root"),
"system", "service",
@@ -71,7 +75,7 @@ var _ = Describe("Systemd activate", func() {
// Curried functions for specialized podman calls
podmanRemote := func(args ...string) *testUtils.PodmanSession {
- args = append([]string{"--url", fmt.Sprintf("tcp://%s:%d", host, port)}, args...)
+ args = append([]string{"--url", "tcp://" + addr}, args...)
return testUtils.SystemExec(podmanTest.RemotePodmanBinary, args)
}
@@ -103,4 +107,37 @@ var _ = Describe("Systemd activate", func() {
Expect(abiSession).To(Exit(0))
Expect(abiSession.OutputToString()).To(Equal("true"))
})
+
+ It("invalid systemd file descriptor", func() {
+ host := "127.0.0.1"
+ port, err := podmanUtils.GetRandomPort()
+ Expect(err).ToNot(HaveOccurred())
+
+ addr := net.JoinHostPort(host, strconv.Itoa(port))
+
+ // start systemd activation with datagram socket
+ activateSession := testUtils.StartSystemExec(activate, []string{
+ "--datagram", "--listen", addr,
+ podmanTest.PodmanBinary,
+ "--root=" + filepath.Join(tempDir, "server_root"),
+ "system", "service",
+ "--time=0",
+ })
+ Expect(activateSession.Exited).ShouldNot(Receive(), "Failed to start podman service")
+
+ // we have to wait for systemd-socket-activate to become ready
+ time.Sleep(1 * time.Second)
+
+ // now dial the socket to start podman
+ conn, err := net.Dial("udp", addr)
+ Expect(err).ToNot(HaveOccurred())
+ defer conn.Close()
+ _, err = conn.Write([]byte("test"))
+ Expect(err).ToNot(HaveOccurred())
+
+ // wait for podman to exit
+ activateSession.Wait(10)
+ Expect(activateSession).To(Exit(125))
+ Expect(activateSession.ErrorToString()).To(ContainSubstring("Error: unexpected fd received from systemd: cannot listen on it"))
+ })
})
diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go
index a1a080904..7b3552cc2 100644
--- a/test/e2e/systemd_test.go
+++ b/test/e2e/systemd_test.go
@@ -60,7 +60,7 @@ WantedBy=default.target
Expect(stop).Should(Exit(0))
}()
- create := podmanTest.Podman([]string{"create", "--name", "redis", redis})
+ create := podmanTest.Podman([]string{"create", "--name", "redis", REDIS_IMAGE})
create.WaitWithDefaultTimeout()
Expect(create).Should(Exit(0))
diff --git a/test/e2e/tree_test.go b/test/e2e/tree_test.go
index e1282d2b4..5b552e987 100644
--- a/test/e2e/tree_test.go
+++ b/test/e2e/tree_test.go
@@ -36,7 +36,7 @@ var _ = Describe("Podman image tree", func() {
It("podman image tree", func() {
SkipIfRemote("podman-image-tree is not supported for remote clients")
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
dockerfile := `FROM quay.io/libpod/cirros:latest
RUN mkdir hello
RUN touch test.txt
diff --git a/test/e2e/untag_test.go b/test/e2e/untag_test.go
index 90b0cc95f..b53d654f8 100644
--- a/test/e2e/untag_test.go
+++ b/test/e2e/untag_test.go
@@ -33,8 +33,8 @@ var _ = Describe("Podman untag", func() {
})
It("podman untag all", func() {
- podmanTest.AddImageToRWStore(cirros)
- tags := []string{cirros, "registry.com/foo:bar", "localhost/foo:bar"}
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
+ tags := []string{CIRROS_IMAGE, "registry.com/foo:bar", "localhost/foo:bar"}
cmd := []string{"tag"}
cmd = append(cmd, tags...)
@@ -50,7 +50,7 @@ var _ = Describe("Podman untag", func() {
}
// No arguments -> remove all tags.
- session = podmanTest.Podman([]string{"untag", cirros})
+ session = podmanTest.Podman([]string{"untag", CIRROS_IMAGE})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -63,7 +63,7 @@ var _ = Describe("Podman untag", func() {
})
It("podman tag/untag - tag normalization", func() {
- podmanTest.AddImageToRWStore(cirros)
+ podmanTest.AddImageToRWStore(CIRROS_IMAGE)
tests := []struct {
tag, normalized string
@@ -77,7 +77,7 @@ var _ = Describe("Podman untag", func() {
// Make sure that the user input is normalized correctly for
// `podman tag` and `podman untag`.
for _, tt := range tests {
- session := podmanTest.Podman([]string{"tag", cirros, tt.tag})
+ session := podmanTest.Podman([]string{"tag", CIRROS_IMAGE, tt.tag})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
@@ -85,7 +85,7 @@ var _ = Describe("Podman untag", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"untag", cirros, tt.tag})
+ session = podmanTest.Podman([]string{"untag", CIRROS_IMAGE, tt.tag})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 0bf5acbf1..7a975f6a5 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -110,15 +110,24 @@ var _ = Describe("Podman volume create", func() {
Expect(session.OutputToString()).To(ContainSubstring("hello"))
})
- It("podman import volume should fail", func() {
+ It("podman import/export volume should fail", func() {
// try import on volume or source which does not exists
- if podmanTest.RemoteTest {
- Skip("Volume export check does not work with a remote client")
- }
+ SkipIfRemote("Volume export check does not work with a remote client")
session := podmanTest.Podman([]string{"volume", "import", "notfound", "notfound.tar"})
session.WaitWithDefaultTimeout()
Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("open notfound.tar: no such file or directory"))
+
+ session = podmanTest.Podman([]string{"volume", "import", "notfound", "-"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound"))
+
+ session = podmanTest.Podman([]string{"volume", "export", "notfound"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound"))
})
It("podman create volume with bad volume option", func() {
@@ -153,4 +162,19 @@ var _ = Describe("Podman volume create", func() {
Expect(inspectOpts).Should(Exit(0))
Expect(inspectOpts.OutputToString()).To(Equal(optionStrFormatExpect))
})
+
+ It("podman create volume with o=timeout", func() {
+ volName := "testVol"
+ timeout := 10
+ timeoutStr := "10"
+ session := podmanTest.Podman([]string{"volume", "create", "--opt", fmt.Sprintf("o=timeout=%d", timeout), volName})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ inspectTimeout := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .Timeout }}", volName})
+ inspectTimeout.WaitWithDefaultTimeout()
+ Expect(inspectTimeout).Should(Exit(0))
+ Expect(inspectTimeout.OutputToString()).To(Equal(timeoutStr))
+
+ })
})
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index 19f87fb8a..dcfb13f4e 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -152,6 +152,37 @@ var _ = Describe("Podman volume ls", func() {
Expect(lsDangling).Should(Exit(0))
Expect(lsDangling.OutputToString()).To(ContainSubstring(volName1))
})
+
+ It("podman ls volume with --filter name", func() {
+ volName1 := "volume1"
+ session := podmanTest.Podman([]string{"volume", "create", volName1})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+
+ volName2 := "volume2"
+ session2 := podmanTest.Podman([]string{"volume", "create", volName2})
+ session2.WaitWithDefaultTimeout()
+ Expect(session2).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls", "--filter", "name=volume1*"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(HaveLen(3))
+ Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName1))
+ Expect(session.OutputToStringArray()[2]).To(ContainSubstring(volName2))
+
+ session = podmanTest.Podman([]string{"volume", "ls", "--filter", "name=volumex"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(BeEmpty())
+
+ session = podmanTest.Podman([]string{"volume", "ls", "--filter", "name=volume1"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).Should(Exit(0))
+ Expect(session.OutputToStringArray()).To(HaveLen(2))
+ Expect(session.OutputToStringArray()[1]).To(ContainSubstring(volName1))
+ })
+
It("podman ls volume with multiple --filter flag", func() {
session := podmanTest.Podman([]string{"volume", "create", "--label", "foo=bar", "myvol"})
volName := session.OutputToString()
diff --git a/test/e2e/volume_plugin_test.go b/test/e2e/volume_plugin_test.go
index 4700afdb5..b585f8dd8 100644
--- a/test/e2e/volume_plugin_test.go
+++ b/test/e2e/volume_plugin_test.go
@@ -6,6 +6,7 @@ import (
"path/filepath"
. "github.com/containers/podman/v4/test/utils"
+ "github.com/containers/storage/pkg/stringid"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
@@ -188,4 +189,71 @@ var _ = Describe("Podman volume plugins", func() {
rmAll.WaitWithDefaultTimeout()
Expect(rmAll).Should(Exit(0))
})
+
+ It("podman volume reload", func() {
+ podmanTest.AddImageToRWStore(volumeTest)
+
+ confFile := filepath.Join(podmanTest.TempDir, "containers.conf")
+ err := os.WriteFile(confFile, []byte(`[engine]
+[engine.volume_plugins]
+testvol5 = "/run/docker/plugins/testvol5.sock"`), 0o644)
+ Expect(err).ToNot(HaveOccurred())
+ os.Setenv("CONTAINERS_CONF", confFile)
+
+ pluginStatePath := filepath.Join(podmanTest.TempDir, "volumes")
+ err = os.Mkdir(pluginStatePath, 0755)
+ Expect(err).ToNot(HaveOccurred())
+
+ // Keep this distinct within tests to avoid multiple tests using the same plugin.
+ pluginName := "testvol5"
+ ctrName := "pluginCtr"
+ plugin := podmanTest.Podman([]string{"run", "--name", ctrName, "--security-opt", "label=disable", "-v", "/run/docker/plugins:/run/docker/plugins",
+ "-v", fmt.Sprintf("%v:%v", pluginStatePath, pluginStatePath), "-d", volumeTest, "--sock-name", pluginName, "--path", pluginStatePath})
+ plugin.WaitWithDefaultTimeout()
+ Expect(plugin).Should(Exit(0))
+
+ localvol := "local-" + stringid.GenerateNonCryptoID()
+ // create local volume
+ session := podmanTest.Podman([]string{"volume", "create", localvol})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+
+ vol1 := "vol1-" + stringid.GenerateNonCryptoID()
+ session = podmanTest.Podman([]string{"volume", "create", "--driver", pluginName, vol1})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+
+ // now create volume in plugin without podman
+ vol2 := "vol2-" + stringid.GenerateNonCryptoID()
+ plugin = podmanTest.Podman([]string{"exec", ctrName, "/usr/local/bin/testvol", "--sock-name", pluginName, "create", vol2})
+ plugin.WaitWithDefaultTimeout()
+ Expect(plugin).Should(Exit(0))
+
+ session = podmanTest.Podman([]string{"volume", "ls", "-q"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ Expect(session.OutputToStringArray()).To(ContainElements(localvol, vol1))
+ Expect(session.ErrorToString()).To(Equal("")) // make sure no errors are shown
+
+ plugin = podmanTest.Podman([]string{"exec", ctrName, "/usr/local/bin/testvol", "--sock-name", pluginName, "remove", vol1})
+ plugin.WaitWithDefaultTimeout()
+ Expect(plugin).Should(Exit(0))
+
+ // now reload volumes from plugins
+ session = podmanTest.Podman([]string{"volume", "reload"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ Expect(string(session.Out.Contents())).To(Equal(fmt.Sprintf(`Added:
+%s
+Removed:
+%s
+`, vol2, vol1)))
+ Expect(session.ErrorToString()).To(Equal("")) // make sure no errors are shown
+
+ session = podmanTest.Podman([]string{"volume", "ls", "-q"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(Exit(0))
+ Expect(session.OutputToStringArray()).To(ContainElements(localvol, vol2))
+ Expect(session.ErrorToString()).To(Equal("")) // make no errors are shown
+ })
})
diff --git a/test/framework/framework.go b/test/framework/framework.go
index 57c6bda2a..26e8bf21c 100644
--- a/test/framework/framework.go
+++ b/test/framework/framework.go
@@ -37,7 +37,7 @@ func NilFunc(f *TestFramework) error {
func (t *TestFramework) Setup() {
// Global initialization for the whole framework goes in here
- // Setup the actual test suite
+ // Set up the actual test suite
gomega.Expect(t.setup(t)).To(gomega.Succeed())
}
diff --git a/test/system/010-images.bats b/test/system/010-images.bats
index 257508418..69ed1004c 100644
--- a/test/system/010-images.bats
+++ b/test/system/010-images.bats
@@ -158,6 +158,11 @@ Labels.created_at | 20[0-9-]\\\+T[0-9:]\\\+Z
# start here because this is the first one, fix this problem.
# You can (probably) ignore any subsequent failures showing '@sha'
# in the error output.
+ #
+ # WARNING! This test is likely to fail for an hour or so after
+ # building a new testimage (via build-testimage script), because
+ # two consecutive 'podman images' may result in a one-minute
+ # difference in the "XX minutes ago" output. This is OK to ignore.
run_podman images -a
is "$output" "$images_baseline" "images -a, after pull: same as before"
diff --git a/test/system/015-help.bats b/test/system/015-help.bats
index 5757d51dc..dd5a7ed44 100644
--- a/test/system/015-help.bats
+++ b/test/system/015-help.bats
@@ -34,10 +34,16 @@ function check_help() {
# has no ' [options]'
is "$usage " " $command_string .*" "Usage string matches command"
+ # Strip off the leading command string; we no longer need it
+ usage=$(sed -e "s/^ $command_string \?//" <<<"$usage")
+
# If usage ends in '[command]', recurse into subcommands
- if expr "$usage" : '.*\[command\]$' >/dev/null; then
+ if expr "$usage" : '\[command\]' >/dev/null; then
found[subcommands]=1
- check_help "$@" $cmd
+ # (except for 'podman help', which is a special case)
+ if [[ $cmd != "help" ]]; then
+ check_help "$@" $cmd
+ fi
continue
fi
@@ -49,10 +55,26 @@ function check_help() {
assert "$usage" !~ '[A-Z].*\[option' \
"'options' must precede arguments in usage"
+ # Strip off '[options]' but remember if we've seen it.
+ local has_options=
+ if [[ $usage =~ \[options\] ]]; then
+ has_options=1
+ usage=$(sed -e 's/^\[options\] \?//' <<<"$usage")
+ fi
+
+ # From this point on, remaining argument descriptions must be UPPER CASE
+ # e.g., 'podman cmd [options] arg' or 'podman cmd [arg]' are invalid.
+ assert "$usage" !~ '[a-z]' \
+ "$command_string: argument names must be UPPER CASE"
+
+ # It makes no sense to have an optional arg followed by a mandatory one
+ assert "$usage" !~ '\[.*\] [A-Z]' \
+ "$command_string: optional args must be _after_ required ones"
+
# Cross-check: if usage includes '[options]', there must be a
# longer 'Options:' section in the full --help output; vice-versa,
# if 'Options:' is in full output, usage line must have '[options]'.
- if expr "$usage" : '.*\[option' >/dev/null; then
+ if [[ $has_options ]]; then
if ! expr "$full_help" : ".*Options:" >/dev/null; then
die "$command_string: Usage includes '[options]' but has no 'Options:' subsection"
fi
@@ -95,9 +117,7 @@ function check_help() {
fi
# If usage has required arguments, try running without them.
- # The expression here is 'first capital letter is not in [BRACKETS]'.
- # It is intended to handle 'podman foo [options] ARG' but not ' [ARG]'.
- if expr "$usage" : '[^A-Z]\+ [A-Z]' >/dev/null; then
+ if expr "$usage" : '[A-Z]' >/dev/null; then
# Exceptions: these commands don't work rootless
if is_rootless; then
# "pause is not supported for rootless containers"
@@ -126,25 +146,15 @@ function check_help() {
# the required args, then invoke with one extra. We should get a
# usage error.
if ! expr "$usage" : ".*\.\.\."; then
- # "podman help" can take infinite args, so skip that one
- if [ "$cmd" != "help" ]; then
- # Get the args part of the command line; this should be
- # everything from the first CAPITAL LETTER onward. We
- # don't actually care about the letter itself, so just
- # make it 'X'. And we don't care about [OPTIONAL] brackets
- # either. What we do care about is stuff like 'IMAGE | CTR'
- # which is actually one argument; convert to 'IMAGE-or-CTR'
- local rhs=$(sed -e 's/^[^A-Z]\+[A-Z]/X/' -e 's/ | /-or-/g' <<<"$usage")
- local n_args=$(wc -w <<<"$rhs")
-
- run_podman '?' "$@" $cmd $(seq --format='x%g' 0 $n_args)
- is "$status" 125 \
- "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected this exit status"
- is "$output" "Error:.* \(takes no arguments\|requires exactly $n_args arg\|accepts at most\|too many arguments\|accepts $n_args arg(s), received\|accepts between .* and .* arg(s), received \)" \
- "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected one of these error messages"
+ local n_args=$(wc -w <<<"$usage")
- found[fixed_args]=1
- fi
+ run_podman '?' "$@" $cmd $(seq --format='x%g' 0 $n_args)
+ is "$status" 125 \
+ "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected this exit status"
+ is "$output" "Error:.* \(takes no arguments\|requires exactly $n_args arg\|accepts at most\|too many arguments\|accepts $n_args arg(s), received\|accepts between .* and .* arg(s), received \)" \
+ "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected one of these error messages"
+
+ found[fixed_args]=1
fi
count=$(expr $count + 1)
@@ -189,7 +199,7 @@ function check_help() {
check_help
# Test for regression of #7273 (spurious "--remote" help on output)
- for helpopt in help --help; do
+ for helpopt in help --help -h; do
run_podman $helpopt
is "${lines[0]}" "Manage pods, containers and images" \
"podman $helpopt: first line of output"
diff --git a/test/system/030-run.bats b/test/system/030-run.bats
index 283c3aea9..b3e3cef00 100644
--- a/test/system/030-run.bats
+++ b/test/system/030-run.bats
@@ -34,12 +34,8 @@ echo $rand | 0 | $rand
# FIXME: The </dev/null is a hack, necessary because as of 2019-09
# podman-remote has a bug in which it silently slurps up stdin,
# including the output of parse_table (i.e. tests to be run).
- run_podman $expected_rc run $IMAGE "$@" </dev/null
-
- # FIXME: remove conditional once podman-remote issue #4096 is fixed
- if ! is_remote; then
- is "$output" "$expected_output" "podman run $cmd - output"
- fi
+ run_podman $expected_rc run $IMAGE "$@"
+ is "$output" "$expected_output" "podman run $cmd - output"
tests_run=$(expr $tests_run + 1)
done < <(parse_table "$tests")
@@ -380,17 +376,7 @@ json-file | f
while read driver do_check; do
msg=$(random_string 15)
run_podman run --name myctr --log-driver $driver $IMAGE echo $msg
-
- # Simple output check
- # Special case: 'json-file' emits a warning, the rest do not
- # ...but with podman-remote the warning is on the server only
- if [[ $do_check == 'f' ]] && ! is_remote; then # 'f' for 'fallback'
- is "${lines[0]}" ".* level=error msg=\"json-file logging specified but not supported. Choosing k8s-file logging instead\"" \
- "Fallback warning emitted"
- is "${lines[1]}" "$msg" "basic output sanity check (driver=$driver)"
- else
- is "$output" "$msg" "basic output sanity check (driver=$driver)"
- fi
+ is "$output" "$msg" "basic output sanity check (driver=$driver)"
# Simply confirm that podman preserved our argument as-is
run_podman inspect --format '{{.HostConfig.LogConfig.Type}}' myctr
@@ -470,10 +456,10 @@ json-file | f
# dependent, we pick an obscure zone (+1245) that is unlikely to
# collide with any of our testing environments.
#
- # To get a reference timestamp we run 'date' locally; note the explicit
- # strftime() format. We can't use --iso=seconds because GNU date adds
- # a colon to the TZ offset (eg -07:00) whereas alpine does not (-0700).
- run date --date=@1600000000 +%Y-%m-%dT%H:%M:%S%z
+ # To get a reference timestamp we run 'date' locally. This requires
+ # that GNU date output matches that of alpine; this seems to be true
+ # as of testimage:20220615.
+ run date --date=@1600000000 --iso=seconds
expect="$output"
TZ=Pacific/Chatham run_podman run --rm --tz=local $IMAGE date -Iseconds -r $testfile
is "$output" "$expect" "podman run with --tz=local, matches host"
@@ -628,7 +614,8 @@ json-file | f
run_podman image mount $IMAGE
romount="$output"
- run_podman run --rm --rootfs $romount echo "Hello world"
+ # FIXME FIXME FIXME: Remove :O once (if) #14504 is fixed!
+ run_podman run --rm --rootfs $romount:O echo "Hello world"
is "$output" "Hello world"
run_podman image unmount $IMAGE
@@ -743,7 +730,7 @@ EOF
run_podman 125 run --device-cgroup-rule="x 7:* rmw" --rm $IMAGE
is "$output" "Error: invalid device type in device-access-add: x"
run_podman 125 run --device-cgroup-rule="a a:* rmw" --rm $IMAGE
- is "$output" "Error: strconv.ParseInt: parsing \"a\": invalid syntax"
+ is "$output" "Error: strconv.ParseUint: parsing \"a\": invalid syntax"
}
@test "podman run closes stdin" {
@@ -855,4 +842,15 @@ EOF
run_podman rmi $test_image
}
+@test "podman create --security-opt" {
+ run_podman create --security-opt no-new-privileges=true $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges:true $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges=false $IMAGE
+ run_podman rm $output
+ run_podman create --security-opt no-new-privileges $IMAGE
+ run_podman rm $output
+}
+
# vim: filetype=sh
diff --git a/test/system/050-stop.bats b/test/system/050-stop.bats
index c2dfba84d..39002512b 100644
--- a/test/system/050-stop.bats
+++ b/test/system/050-stop.bats
@@ -171,4 +171,19 @@ load helpers
run_podman --noout stop -t 0 stopme
is "$output" "" "output should be empty"
}
+
+@test "podman stop, with --rm container" {
+ OCIDir=/run/$(podman_runtime)
+
+ if is_rootless; then
+ OCIDir=/run/user/$(id -u)/$(podman_runtime)
+ fi
+
+ run_podman run --rm -d --name rmstop $IMAGE sleep infinity
+ local cid="$output"
+ run_podman stop rmstop
+
+ # Check the OCI runtime directory has removed.
+ is "$(ls $OCIDir | grep $cid)" "" "The OCI runtime directory should have been removed"
+}
# vim: filetype=sh
diff --git a/test/system/055-rm.bats b/test/system/055-rm.bats
index 69663fafa..0ef2216b8 100644
--- a/test/system/055-rm.bats
+++ b/test/system/055-rm.bats
@@ -52,10 +52,20 @@ load helpers
}
@test "podman rm <-> run --rm race" {
+ OCIDir=/run/$(podman_runtime)
+
+ if is_rootless; then
+ OCIDir=/run/user/$(id -u)/$(podman_runtime)
+ fi
+
# A container's lock is released before attempting to stop it. This opens
# the window for race conditions that led to #9479.
run_podman run --rm -d $IMAGE sleep infinity
+ local cid="$output"
run_podman rm -af
+
+ # Check the OCI runtime directory has removed.
+ is "$(ls $OCIDir | grep $cid)" "" "The OCI runtime directory should have been removed"
}
@test "podman rm --depend" {
diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats
index 7addbd88e..4498e675f 100644
--- a/test/system/060-mount.bats
+++ b/test/system/060-mount.bats
@@ -50,6 +50,10 @@ load helpers
run_podman image mount $IMAGE
mount_path="$output"
+ # Make sure that `mount -a` prints a table
+ run_podman image mount -a
+ is "$output" "$IMAGE .*$mount_path"
+
test -d $mount_path
# Image is custom-built and has a file containing the YMD tag. Check it.
@@ -62,8 +66,8 @@ load helpers
run_podman image mount
is "$output" "$IMAGE *$mount_path" "podman image mount with no args"
- # Clean up
- run_podman image umount $IMAGE
+ # Clean up: -f since we mounted it twice
+ run_podman image umount -f $IMAGE
is "$output" "$iid" "podman image umount: image ID of what was umounted"
run_podman image umount $IMAGE
@@ -83,7 +87,7 @@ load helpers
# Run a container with an image mount
run_podman run --rm --mount type=image,src=$IMAGE,dst=/image-mount $IMAGE diff /etc/os-release /image-mount/etc/os-release
- # Make sure the mount is read only
+ # Make sure the mount is read-only
run_podman 1 run --rm --mount type=image,src=$IMAGE,dst=/image-mount $IMAGE touch /image-mount/read-only
is "$output" "touch: /image-mount/read-only: Read-only file system"
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index cfbeff3ae..8f5abd228 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -66,7 +66,7 @@ load helpers
# Container (parent) path does not exist.
run_podman 125 cp $srcdir/hostfile0 cpcontainer:/IdoNotExist/
- is "$output" 'Error: "/IdoNotExist/" could not be found on container cpcontainer: No such file or directory' \
+ is "$output" 'Error: "/IdoNotExist/" could not be found on container cpcontainer: no such file or directory' \
"copy into nonexistent path in container"
run_podman kill cpcontainer
@@ -794,7 +794,7 @@ ${randomcontent[1]}" "$description"
is "$output" "" "output from podman cp 1"
run_podman 125 cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/
- is "$output" 'Error: "/tmp/d2/x/" could not be found on container cpcontainer: No such file or directory' "cp will not create nonexistent destination directory"
+ is "$output" 'Error: "/tmp/d2/x/" could not be found on container cpcontainer: no such file or directory' "cp will not create nonexistent destination directory"
run_podman cp --pause=false $srcdir/$rand_filename3 cpcontainer:/tmp/d3/x
is "$output" "" "output from podman cp 3"
@@ -949,9 +949,107 @@ ${randomcontent[1]}" "$description"
run_podman rm -t 0 -f cpcontainer
}
+@test "podman cp --overwrite file - ctr/ctr" {
+ rand_content_file=$(random_string 50)
+ rand_content_dir=$(random_string 50)
+
+ run_podman run -d --name ctr-file $IMAGE sh -c "echo '$rand_content_file' > /tmp/foo; sleep infinity"
+ run_podman run -d --name ctr-dir $IMAGE sh -c "mkdir /tmp/foo; echo '$rand_content_dir' > /tmp/foo/file.txt; sleep infinity"
+
+ # overwrite a directory with a file
+ run_podman 125 cp ctr-file:/tmp/foo ctr-dir:/tmp
+ if ! is_remote; then # remote just returns a 500
+ is "$output" ".* error creating \"/tmp/foo\": .*: file exists.*"
+ fi
+ run_podman cp --overwrite ctr-file:/tmp/foo ctr-dir:/tmp
+ run_podman exec ctr-dir cat /tmp/foo
+ is "$output" "$rand_content_file"
+
+ # reset the ctr-dir container
+ run_podman exec ctr-dir sh -c "rm -rf /tmp/foo; mkdir /tmp/foo; echo '$rand_content_dir' > /tmp/foo/file.txt"
+
+ # overwrite a file with a directory
+ run_podman 125 cp ctr-dir:/tmp/foo ctr-file:/tmp
+ if ! is_remote; then # remote just returns a 500
+ is "$output" ".* error creating \"/tmp/foo\": .*: file exists.*"
+ fi
+ run_podman cp --overwrite ctr-dir:/tmp/foo ctr-file:/tmp
+ run_podman exec ctr-file cat /tmp/foo/file.txt
+ is "$output" "$rand_content_dir"
+
+ run_podman rm -t 0 -f ctr-file ctr-dir
+}
+
+@test "podman cp --overwrite file - ctr/host" {
+ hostdir=$PODMAN_TMPDIR/cp-test
+ mkdir -p $hostdir
+
+ rand_content_file=$(random_string 50)
+ rand_content_dir=$(random_string 50)
+
+ run_podman run -d --name ctr-file $IMAGE sh -c "echo '$rand_content_file' > /tmp/foo; sleep infinity"
+ run_podman run -d --name ctr-dir $IMAGE sh -c "mkdir /tmp/foo; echo '$rand_content_dir' > /tmp/foo/file.txt; sleep infinity"
+
+ # overwrite a directory with a file
+ mkdir $hostdir/foo
+ run_podman 125 cp ctr-file:/tmp/foo $hostdir
+ if ! is_remote; then # remote just returns a 500
+ is "$output" ".* error creating \"/foo\": .*: file exists.*"
+ fi
+ run_podman cp --overwrite ctr-file:/tmp/foo $hostdir
+ is "$(< $hostdir/foo)" "$rand_content_file"
+
+ # overwrite a file with a directory
+ rm -rf $hostdir/foo
+ touch $hostdir/foo
+ run_podman 125 cp ctr-dir:/tmp/foo $hostdir
+ if ! is_remote; then # remote just returns a 500
+ is "$output" ".* error creating \"/foo\": .*: file exists.*"
+ fi
+ run_podman cp --overwrite ctr-dir:/tmp/foo $hostdir
+ is "$(< $hostdir/foo/file.txt)" "$rand_content_dir"
+
+ run_podman rm -t 0 -f ctr-file ctr-dir
+}
+
+@test "podman cp --overwrite file - host/ctr" {
+ hostdir=$PODMAN_TMPDIR/cp-test
+ mkdir -p $hostdir
+
+ rand_content_file=$(random_string 50)
+ rand_content_dir=$(random_string 50)
+
+ run_podman run -d --name ctr-dir $IMAGE sh -c "mkdir /tmp/foo; sleep infinity"
+ run_podman run -d --name ctr-file $IMAGE sh -c "touch /tmp/foo; sleep infinity"
+
+ # overwrite a directory with a file
+ echo "$rand_content_file" > $hostdir/foo
+ run_podman 125 cp $hostdir/foo ctr-dir:/tmp
+ if ! is_remote; then # remote just returns a 500
+ is "$output" ".* error creating \"/tmp/foo\": .*: file exists.*"
+ fi
+ run_podman cp --overwrite $hostdir/foo ctr-dir:/tmp
+ run_podman exec ctr-dir cat /tmp/foo
+ is "$output" "$rand_content_file"
+
+ # overwrite a file with a directory
+ rm -f $hostdir/foo
+ mkdir $hostdir/foo
+ echo "$rand_content_dir" > $hostdir/foo/file.txt
+ run_podman 125 cp $hostdir/foo ctr-file:/tmp
+ if ! is_remote; then # remote just returns a 500
+ is "$output" ".* error creating \"/tmp/foo\": .*: file exists.*"
+ fi
+ run_podman cp --overwrite $hostdir/foo ctr-file:/tmp
+ run_podman exec ctr-file cat /tmp/foo/file.txt
+ is "$output" "$rand_content_dir"
+
+ run_podman rm -t 0 -f ctr-file ctr-dir
+}
+
function teardown() {
# In case any test fails, clean up the container we left behind
- run_podman rm -t 0 f cpcontainer
+ run_podman rm -t 0 -f --ignore cpcontainer
basic_teardown
}
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index b7e0ab447..9fddbaa21 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -496,7 +496,12 @@ Labels.$label_name | $label_value
"image tree: third line"
is "${lines[3]}" "Image Layers" \
"image tree: fourth line"
- is "${lines[4]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[$IMAGE]" \
+ # FIXME: if #14536 is ever fixed, rebuild testimage & s/5/4/ below.
+ # Summary: this should be ${lines[4]}, not [5], and prior to 2022-06-15
+ # it was. Unfortunately, a nightmarish bug interaction makes it impossible
+ # for us to use --squash-all on our testimage. Unless/until that bug is
+ # fixed, we have an extra layer that all we can do is ignore.
+ is "${lines[5]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[$IMAGE]" \
"image tree: first layer line"
is "${lines[-1]}" ".* ID: [0-9a-f]\{12\} Size: .* Top Layer of: \[localhost/build_test:latest]" \
"image tree: last layer line"
@@ -757,7 +762,7 @@ EOF
is "$output" "[no instance of 'Using cache']" "no cache used"
fi
- run_podman rmi -a --force
+ run_podman rmi -f build_test
}
# Caveat lector: this test was mostly copy-pasted from buildah in #9275.
diff --git a/test/system/120-load.bats b/test/system/120-load.bats
index 45e0b3362..7f0bcfd95 100644
--- a/test/system/120-load.bats
+++ b/test/system/120-load.bats
@@ -121,15 +121,31 @@ verify_iid_and_name() {
run_podman untag $IMAGE $newname
run_podman image scp -q ${notme}@localhost::$newname
- expect="Loaded image(s): $newname"
+ expect="Loaded image: $newname"
is "$output" "$expect" "-q silences output"
# Confirm that we have it, and that its digest matches our original
run_podman image inspect --format '{{.Digest}}' $newname
is "$output" "$src_digest" "Digest of re-fetched image matches original"
- # Clean up
+ # test tagging capability
+ run_podman untag $IMAGE $newname
+ run_podman image scp ${notme}@localhost::$newname foobar:123
+
+ run_podman image inspect --format '{{.Digest}}' foobar:123
+ is "$output" "$src_digest" "Digest of re-fetched image matches original"
+
+ # remove root img for transfer back with another name
_sudo $PODMAN image rm $newname
+
+ # get foobar's ID, for an ID transfer test
+ run_podman image inspect --format '{{.ID}}' foobar:123
+ run_podman image scp $output ${notme}@localhost::foobartwo
+
+ _sudo $PODMAN image exists foobartwo
+
+ # Clean up
+ _sudo $PODMAN image rm foobartwo
run_podman untag $IMAGE $newname
# Negative test for nonexistent image.
@@ -142,12 +158,6 @@ verify_iid_and_name() {
run_podman 125 image scp $nope ${notme}@localhost::
is "$output" "Error: $nope: image not known.*" "Pushing nonexistent image"
- # Negative test for copying to a different name
- run_podman 125 image scp $IMAGE ${notme}@localhost::newname:newtag
- is "$output" "Error: cannot specify an image rename: invalid argument" \
- "Pushing with a different name: not allowed"
-
- # FIXME: any point in copying by image ID? What else should we test?
}
diff --git a/test/system/130-kill.bats b/test/system/130-kill.bats
index a9456e03c..96b633a42 100644
--- a/test/system/130-kill.bats
+++ b/test/system/130-kill.bats
@@ -130,4 +130,14 @@ load helpers
is "$output" $cname
}
+@test "podman kill - concurrent stop" {
+ # 14761 - concurrent kill/stop must record the exit code
+ random_name=$(random_string 10)
+ run_podman run -d --replace --name=$random_name alpine sh -c "trap 'echo Received SIGTERM, ignoring' SIGTERM; echo READY; while :; do sleep 0.2; done"
+ $PODMAN stop -t 1 $random_name &
+ run_podman kill $random_name
+ run_podman wait $random_name
+ run_podman rm -f $random_name
+}
+
# vim: filetype=sh
diff --git a/test/system/150-login.bats b/test/system/150-login.bats
index 33b8438bf..dc902d5fe 100644
--- a/test/system/150-login.bats
+++ b/test/system/150-login.bats
@@ -314,7 +314,7 @@ function _test_skopeo_credential_sharing() {
fi
# Make sure socket is closed
- if { exec 3<> /dev/tcp/127.0.0.1/${PODMAN_LOGIN_REGISTRY_PORT}; } &>/dev/null; then
+ if ! port_is_free $PODMAN_LOGIN_REGISTRY_PORT; then
die "Socket still seems open"
fi
}
diff --git a/test/system/160-volumes.bats b/test/system/160-volumes.bats
index 5b0460723..da60112a0 100644
--- a/test/system/160-volumes.bats
+++ b/test/system/160-volumes.bats
@@ -64,6 +64,29 @@ function teardown() {
}
+# Filter volumes by name
+@test "podman volume filter --name" {
+ suffix=$(random_string)
+ prefix="volume"
+
+ for i in 1 2; do
+ myvolume=${prefix}_${i}_${suffix}
+ run_podman volume create $myvolume
+ is "$output" "$myvolume" "output from volume create $i"
+ done
+
+ run_podman volume ls --filter name=${prefix}_1.+ --format "{{.Name}}"
+ is "$output" "${prefix}_1_${suffix}" "--filter name=${prefix}_1.+ shows only one volume"
+
+ # The _1* is intentional as asterisk has different meaning in glob and regexp. Make sure this is regexp
+ run_podman volume ls --filter name=${prefix}_1* --format "{{.Name}}"
+ is "$output" "${prefix}_1_${suffix}.*${prefix}_2_${suffix}.*" "--filter name=${prefix}_1* shows ${prefix}_1_${suffix} and ${prefix}_2_${suffix}"
+
+ for i in 1 2; do
+ run_podman volume rm ${prefix}_${i}_${suffix}
+ done
+}
+
# Named volumes
@test "podman volume create / run" {
myvolume=myvol$(random_string)
@@ -411,4 +434,43 @@ NeedsChown | true
fi
}
+@test "podman --image-volume" {
+ tmpdir=$PODMAN_TMPDIR/volume-test
+ mkdir -p $tmpdir
+ containerfile=$tmpdir/Containerfile
+ cat >$containerfile <<EOF
+FROM $IMAGE
+VOLUME /data
+EOF
+ fs=$(stat -f -c %T .)
+ run_podman build -t volume_image $tmpdir
+
+ containersconf=$tmpdir/containers.conf
+ cat >$containersconf <<EOF
+[engine]
+image_volume_mode="tmpfs"
+EOF
+
+ run_podman run --image-volume tmpfs --rm volume_image stat -f -c %T /data
+ is "$output" "tmpfs" "Should be tmpfs"
+
+ run_podman 1 run --image-volume ignore --rm volume_image stat -f -c %T /data
+ is "$output" "stat: can't read file system information for '/data': No such file or directory" "Should fail with /data does not exists"
+
+ CONTAINERS_CONF="$containersconf" run_podman run --rm volume_image stat -f -c %T /data
+ is "$output" "tmpfs" "Should be tmpfs"
+
+ CONTAINERS_CONF="$containersconf" run_podman run --image-volume bind --rm volume_image stat -f -c %T /data
+ assert "$output" != "tmpfs" "Should match hosts $fs"
+
+ CONTAINERS_CONF="$containersconf" run_podman run --image-volume tmpfs --rm volume_image stat -f -c %T /data
+ is "$output" "tmpfs" "Should be tmpfs"
+
+ CONTAINERS_CONF="$containersconf" run_podman 1 run --image-volume ignore --rm volume_image stat -f -c %T /data
+ is "$output" "stat: can't read file system information for '/data': No such file or directory" "Should fail with /data does not exists"
+
+ run_podman rm --all --force -t 0
+ run_podman image rm --force localhost/volume_image
+}
+
# vim: filetype=sh
diff --git a/test/system/170-run-userns.bats b/test/system/170-run-userns.bats
index b80351902..84788a7f4 100644
--- a/test/system/170-run-userns.bats
+++ b/test/system/170-run-userns.bats
@@ -38,10 +38,12 @@ function _require_crun() {
@test "rootful pod with custom ID mapping" {
skip_if_rootless "does not work rootless - rootful feature"
- skip_if_remote "remote --uidmap is broken (see #14233)"
random_pod_name=$(random_string 30)
run_podman pod create --uidmap 0:200000:5000 --name=$random_pod_name
run_podman pod start $random_pod_name
+ run_podman pod inspect --format '{{.InfraContainerID}}' $random_pod_name
+ run podman inspect --format '{{.HostConfig.IDMappings.UIDMap}}' $output
+ is "$output" ".*0:200000:5000" "UID Map Successful"
# Remove the pod and the pause image
run_podman pod rm $random_pod_name
@@ -109,15 +111,30 @@ EOF
}
@test "podman userns=nomap" {
- skip_if_not_rootless "--userns=nomap only works in rootless mode"
- ns_user=$(id -un)
- baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:)
- test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}"
+ if is_rootless; then
+ ns_user=$(id -un)
+ baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:)
+ test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}"
+
+ test_name="test_$(random_string 12)"
+ run_podman run -d --userns=nomap $IMAGE sleep 100
+ cid=${output}
+ run_podman top ${cid} huser
+ is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID"
+ run_podman rm -t 0 --force ${cid}
+ else
+ run_podman 125 run -d --userns=nomap $IMAGE sleep 100
+ is "${output}" "Error: nomap is only supported in rootless mode" "Container should fail to start since nomap is not suppored in rootful mode"
+ fi
+}
- test_name="test_$(random_string 12)"
- run_podman run -d --userns=nomap $IMAGE sleep 100
- cid=${output}
- run_podman top ${cid} huser
- is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID"
- run_podman rm -t 0 --force ${cid}
+@test "podman userns=keep-id" {
+ if is_rootless; then
+ user=$(id -u)
+ run_podman run --rm --userns=keep-id $IMAGE id -u
+ is "${output}" "$user" "Container should run as the current user"
+ else
+ run_podman 125 run --rm --userns=keep-id $IMAGE id -u
+ is "${output}" "Error: keep-id is only supported in rootless mode" "Container should fail to start since keep-id is not suppored in rootful mode"
+ fi
}
diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats
index 4250f2680..b93f3f92f 100644
--- a/test/system/200-pod.bats
+++ b/test/system/200-pod.bats
@@ -332,11 +332,18 @@ EOF
@test "podman pod create --share" {
local pod_name="$(random_string 10 | tr A-Z a-z)"
run_podman 125 pod create --share bogus --name $pod_name
- is "$output" ".*Invalid kernel namespace to share: bogus. Options are: cgroup, ipc, net, pid, uts or none" \
+ is "$output" ".*invalid kernel namespace to share: bogus. Options are: cgroup, ipc, net, pid, uts or none" \
"pod test for bogus --share option"
run_podman pod create --share ipc --name $pod_name
+ run_podman pod inspect $pod_name --format "{{.SharedNamespaces}}"
+ is "$output" "[ipc]"
run_podman run --rm --pod $pod_name --hostname foobar $IMAGE hostname
is "$output" "foobar" "--hostname should work with non share UTS namespace"
+ run_podman pod create --share +pid --replace --name $pod_name
+ run_podman pod inspect $pod_name --format "{{.SharedNamespaces}}"
+ for ns in uts pid ipc net; do
+ is "$output" ".*$ns"
+ done
}
@test "podman pod create --pod new:$POD --hostname" {
@@ -387,20 +394,20 @@ EOF
is "$output" "false" "Default network sharing should be false"
run_podman pod rm test
- run_podman pod create --name test --share ipc --network private
+ run_podman pod create --share ipc --network private test
run_podman pod inspect test --format {{.InfraConfig.HostNetwork}}
is "$output" "false" "Private network sharing with only ipc should be false"
run_podman pod rm test
- run_podman pod create --name test --share net --network private
- run_podman pod inspect test --format {{.InfraConfig.HostNetwork}}
+ local name="$(random_string 10 | tr A-Z a-z)"
+ run_podman pod create --name $name --share net --network private
+ run_podman pod inspect $name --format {{.InfraConfig.HostNetwork}}
is "$output" "false" "Private network sharing with only net should be false"
- run_podman pod rm test
- run_podman pod create --name test --share net --network host
- run_podman pod inspect test --format {{.InfraConfig.HostNetwork}}
+ run_podman pod create --share net --network host --replace $name
+ run_podman pod inspect $name --format {{.InfraConfig.HostNetwork}}
is "$output" "true" "Host network sharing with only net should be true"
- run_podman pod rm test
+ run_podman pod rm $name
run_podman pod create --name test --share ipc --network host
run_podman pod inspect test --format {{.InfraConfig.HostNetwork}}
@@ -465,4 +472,49 @@ spec:
run_podman pod rm $name-pod
}
+@test "pod resource limits" {
+ skip_if_remote "resource limits only implemented on non-remote"
+ if is_rootless; then
+ skip "only meaningful for rootful"
+ fi
+
+ local name1="resources1"
+ run_podman --cgroup-manager=systemd pod create --name=$name1 --cpus=5 --memory=10m
+ run_podman --cgroup-manager=systemd pod start $name1
+ run_podman pod inspect --format '{{.CgroupPath}}' $name1
+ local path1="$output"
+ local actual1=$(< /sys/fs/cgroup/$path1/cpu.max)
+ is "$actual1" "500000 100000" "resource limits set properly"
+ local actual2=$(< /sys/fs/cgroup/$path1/memory.max)
+ is "$actual2" "10485760" "resource limits set properly"
+ run_podman pod --cgroup-manager=systemd rm -f $name1
+
+ local name2="resources2"
+ run_podman --cgroup-manager=cgroupfs pod create --cpus=5 --memory=10m --name=$name2
+ run_podman --cgroup-manager=cgroupfs pod start $name2
+ run_podman pod inspect --format '{{.CgroupPath}}' $name2
+ local path2="$output"
+ local actual2=$(< /sys/fs/cgroup/$path2/cpu.max)
+ is "$actual2" "500000 100000" "resource limits set properly"
+ local actual2=$(< /sys/fs/cgroup/$path2/memory.max)
+ is "$actual2" "10485760" "resource limits set properly"
+ run_podman --cgroup-manager=cgroupfs pod rm $name2
+}
+
+@test "podman pod ps doesn't race with pod rm" {
+ # create a few pods
+ for i in {0..10}; do
+ run_podman pod create
+ done
+
+ # and delete them
+ $PODMAN pod rm -a &
+
+ # pod ps should not fail while pods are deleted
+ run_podman pod ps -q
+
+ # wait for pod rm -a
+ wait
+}
+
# vim: filetype=sh
diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats
index 567fa89c1..fc3c33975 100644
--- a/test/system/250-systemd.bats
+++ b/test/system/250-systemd.bats
@@ -27,7 +27,6 @@ function teardown() {
rm -f "$UNIT_FILE"
systemctl daemon-reload
fi
- run_podman rmi -a
basic_teardown
}
@@ -53,10 +52,17 @@ function service_setup() {
# Helper to stop a systemd service running a container
function service_cleanup() {
- local status=$1
run systemctl stop "$SERVICE_NAME"
assert $status -eq 0 "Error stopping systemd unit $SERVICE_NAME: $output"
+ # Regression test for #11304: confirm that unit stops into correct state
+ local expected_state="$1"
+ if [[ -n "$expected_state" ]]; then
+ run systemctl show --property=ActiveState "$SERVICE_NAME"
+ assert "$output" = "ActiveState=$expected_state" \
+ "state of service after systemctl stop"
+ fi
+
run systemctl disable "$SERVICE_NAME"
assert $status -eq 0 "Error disabling systemd unit $SERVICE_NAME: $output"
@@ -80,12 +86,6 @@ function service_cleanup() {
run_podman logs $cname
is "$output" ".*WAITING.*" "running is waiting for signal"
- # Exercise `podman auto-update`.
- # TODO: this will at least run auto-update code but won't perform an update
- # since the image didn't change. We need to improve on that and run
- # an image from a local registry instead.
- run_podman auto-update
-
# All good. Stop service, clean up.
# Also make sure the service is in the `inactive` state (see #11304).
service_cleanup inactive
@@ -94,26 +94,28 @@ function service_cleanup() {
@test "podman autoupdate local" {
# Note that the entrypoint may be a JSON string which requires preserving the quotes (see #12477)
cname=$(random_string)
- run_podman create --name $cname --label "io.containers.autoupdate=local" --entrypoint '["top"]' $IMAGE
+
+ # Create a scratch image (copy of our regular one)
+ image_copy=base$(random_string | tr A-Z a-z)
+ run_podman tag $IMAGE $image_copy
+
+ # Create a container based on that
+ run_podman create --name $cname --label "io.containers.autoupdate=local" --entrypoint '["top"]' $image_copy
# Start systemd service to run this container
service_setup
# Give container time to start; make sure output looks top-like
- sleep 2
- run_podman logs $cname
- is "$output" ".*Load average:.*" "running container 'top'-like output"
-
- # Save the container id before updating
- run_podman ps --format '{{.ID}}'
+ wait_for_output 'Load average' $cname
# Run auto-update and check that it restarted the container
- run_podman commit --change "CMD=/bin/bash" $cname $IMAGE
+ run_podman commit --change "CMD=/bin/bash" $cname $image_copy
run_podman auto-update
is "$output" ".*$SERVICE_NAME.*" "autoupdate local restarted container"
# All good. Stop service, clean up.
service_cleanup
+ run_podman rmi $image_copy
}
# These tests can fail in dev. environment because of SELinux.
@@ -241,6 +243,7 @@ LISTEN_FDNAMES=listen_fdnames" | sort)
run_podman rm -f $cname
run_podman pod rm -f $podname
+ run_podman rmi $(pause_image)
}
@test "podman generate - systemd template only used on --new" {
@@ -292,15 +295,17 @@ LISTEN_FDNAMES=listen_fdnames" | sort)
run_podman network rm -f $netname
}
-@test "podman-play-kube@.service template" {
+@test "podman-kube@.service template" {
skip_if_remote "systemd units do not work with remote clients"
# If running from a podman source directory, build and use the source
# version of the play-kube-@ unit file
- unit_name="podman-play-kube@.service"
+ unit_name="podman-kube@.service"
unit_file="contrib/systemd/system/${unit_name}"
if [[ -e ${unit_file}.in ]]; then
echo "# [Building & using $unit_name from source]" >&3
+ # Force regenerating unit file (existing one may have /usr/bin path)
+ rm -f $unit_file
BINDIR=$(dirname $PODMAN) make $unit_file
cp $unit_file $UNIT_DIR/$unit_name
fi
@@ -324,7 +329,7 @@ spec:
EOF
# Dispatch the YAML file
- service_name="podman-play-kube@$(systemd-escape $yaml_source).service"
+ service_name="podman-kube@$(systemd-escape $yaml_source).service"
systemctl start $service_name
systemctl is-active $service_name
@@ -366,6 +371,33 @@ EOF
systemctl stop $service_name
run_podman 1 container exists $service_container
run_podman 1 pod exists test_pod
+ run_podman rmi $(pause_image)
+ rm -f $UNIT_DIR/$unit_name
+}
+
+@test "podman-system-service containers survive service stop" {
+ skip_if_remote "N/A under podman-remote"
+
+ SERVICE_NAME=podman-service-$(random_string)
+ port=$(random_free_port)
+ URL=tcp://127.0.0.1:$port
+
+ systemd-run --unit=$SERVICE_NAME $PODMAN system service $URL --time=0
+ wait_for_port 127.0.0.1 $port
+
+ # Start a long-running container.
+ cname=keeps-running
+ run_podman --url $URL run -d --name $cname $IMAGE top -d 2
+
+ run_podman container inspect -l --format "{{.State.Running}}"
+ is "$output" "true" "This should never fail"
+
+ systemctl stop $SERVICE_NAME
+
+ run_podman container inspect $cname --format "{{.State.Running}}"
+ is "$output" "true" "Container is still running after podman server stops"
+
+ run_podman rm -f -t 0 $cname
}
# vim: filetype=sh
diff --git a/test/system/410-selinux.bats b/test/system/410-selinux.bats
index 21ac4cb8f..d437465a4 100644
--- a/test/system/410-selinux.bats
+++ b/test/system/410-selinux.bats
@@ -205,7 +205,11 @@ function check_label() {
# from /proc/thread-self/attr/exec`: .* unable to assign
# to /proc/self/attr/keycreate`: .* unable to process
crun) expect="\`/proc/.*\`: OCI runtime error: unable to \(assign\|process\) security attribute" ;;
- runc) expect="OCI runtime error: .*: failed to set /proc/self/attr/keycreate on procfs" ;;
+ # runc 1.1 changed the error message because of new selinux pkg that uses standard os.PathError, see
+ # https://github.com/opencontainers/selinux/pull/148/commits/a5dc47f74c56922d58ead05d1fdcc5f7f52d5f4e
+ # from failed to set /proc/self/attr/keycreate on procfs
+ # to write /proc/self/attr/keycreate: invalid argument
+ runc) expect="OCI runtime error: .*: \(failed to set|write\) /proc/self/attr/keycreate" ;;
*) skip "Unknown runtime '$runtime'";;
esac
diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats
index 3db0804d1..50eb15216 100644
--- a/test/system/500-networking.bats
+++ b/test/system/500-networking.bats
@@ -111,6 +111,10 @@ load helpers
$IMAGE nc -l -n -v -p $myport
cid="$output"
+ # check that podman stores the network info correctly when a userns is used (#14465)
+ run_podman container inspect --format "{{.NetworkSettings.SandboxKey}}" $cid
+ assert "$output" =~ ".*/netns/netns-.*" "Netns path should be set"
+
wait_for_output "listening on .*:$myport .*" $cid
# emit random string, and check it
@@ -161,6 +165,9 @@ load helpers
run_podman pod rm $pod_name
is "$output" "$pid" "Only ID in output (no extra errors)"
+
+ # Clean up
+ run_podman rmi $(pause_image)
}
@test "podman run with slirp4ns assigns correct addresses to /etc/hosts" {
@@ -352,7 +359,7 @@ load helpers
run curl -s $SERVER/index.txt
is "$output" "$random_1" "curl 127.0.0.1:/index.txt"
- # cleanup the container
+ # clean up the container
run_podman rm -t 0 -f $cid
# test that we cannot remove the default network
@@ -542,7 +549,7 @@ load helpers
run curl --max-time 3 -s $SERVER/index.txt
is "$output" "$random_1" "curl 127.0.0.1:/index.txt should still work"
- # cleanup
+ # clean up
run_podman rm -t 0 -f $cid $background_cid
run_podman network rm -t 0 -f $netname $netname2
}
@@ -615,7 +622,7 @@ load helpers
run_podman rm -t 0 -f $cid
done
- # Cleanup network
+ # Clean up network
run_podman network rm -t 0 -f $netname
}
@@ -669,17 +676,21 @@ EOF
@test "podman run port forward range" {
for netmode in bridge slirp4netns:port_handler=slirp4netns slirp4netns:port_handler=rootlesskit; do
- local port=$(random_free_port)
- local end_port=$(( $port + 2 ))
- local range="$port-$end_port:$port-$end_port"
+ local range=$(random_free_port_range 3)
+ # die() inside $(...) does not actually stop us.
+ assert "$range" != "" "Could not find free port range"
+
+ local port="${range%-*}"
+ local end_port="${range#*-}"
local random=$(random_string)
- run_podman run --network $netmode -p "$range" -d $IMAGE sleep inf
+ run_podman run --network $netmode -p "$range:$range" -d $IMAGE sleep inf
cid="$output"
for port in $(seq $port $end_port); do
run_podman exec -d $cid nc -l -p $port -e /bin/cat
- # -w 1 adds a 1 second timeout, for some reason ubuntus ncat doesn't close the connection on EOF,
- # other options to change this are not portable across distros but -w seems to work
+ # -w 1 adds a 1 second timeout. For some reason, ubuntu's ncat
+ # doesn't close the connection on EOF, and other options to
+ # change this are not portable across distros. -w seems to work.
run nc -w 1 127.0.0.1 $port <<<$random
is "$output" "$random" "ncat got data back (netmode=$netmode port=$port)"
done
diff --git a/test/system/520-checkpoint.bats b/test/system/520-checkpoint.bats
index c16a8c35d..7f60f01b3 100644
--- a/test/system/520-checkpoint.bats
+++ b/test/system/520-checkpoint.bats
@@ -170,4 +170,34 @@ function teardown() {
# FIXME: test --leave-running
+@test "podman checkpoint --file-locks" {
+ action='flock test.lock sh -c "while [ -e /wait ];do sleep 0.5;done;for i in 1 2 3;do echo \$i;sleep 0.5;done"'
+ run_podman run -d $IMAGE sh -c "touch /wait; touch test.lock; echo READY; $action & $action & wait"
+ local cid="$output"
+
+ # Wait for container to start emitting output
+ wait_for_ready $cid
+
+ # Checkpoint, and confirm via inspect
+ run_podman container checkpoint --file-locks $cid
+ is "$output" "$cid" "podman container checkpoint"
+
+ run_podman container inspect \
+ --format '{{.State.Status}}:{{.State.Running}}:{{.State.Paused}}:{{.State.Checkpointed}}' $cid
+ is "$output" "exited:false:false:true" "State. Status:Running:Pause:Checkpointed"
+
+ # Restart immediately and confirm state
+ run_podman container restore --file-locks $cid
+ is "$output" "$cid" "podman container restore"
+
+ # Signal the container to continue; this is where the 1-2-3s will come from
+ run_podman exec $cid rm /wait
+
+ # Wait for the container to stop
+ run_podman wait $cid
+
+ run_podman logs $cid
+ trim=$(sed -z -e 's/[\r\n]\+//g' <<<"$output")
+ is "$trim" "READY123123" "File lock restored"
+}
# vim: filetype=sh
diff --git a/test/system/600-completion.bats b/test/system/600-completion.bats
index 018e95e78..cb4a2c5f8 100644
--- a/test/system/600-completion.bats
+++ b/test/system/600-completion.bats
@@ -8,6 +8,16 @@
load helpers
+function setup() {
+ # $PODMAN may be a space-separated string, e.g. if we include a --url.
+ local -a podman_as_array=($PODMAN)
+ # __completeNoDesc must be the first arg if we running the completion cmd
+ # set the var for the run_completion function
+ PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}"
+
+ basic_setup
+}
+
# Returns true if we are able to podman-pause
function _can_pause() {
# Even though we're just trying completion, not an actual unpause,
@@ -88,8 +98,14 @@ function check_shell_completion() {
continue 2
fi
+ name=$random_container_name
+ # special case podman cp suggest containers names with a colon
+ if [[ $cmd = "cp" ]]; then
+ name="$name:"
+ fi
+
run_completion "$@" $cmd "${extra_args[@]}" ""
- is "$output" ".*-$random_container_name${nl}" \
+ is "$output" ".*-$name${nl}" \
"$* $cmd: actual container listed in suggestions"
match=true
@@ -175,7 +191,7 @@ function check_shell_completion() {
_check_completion_end NoSpace
else
_check_completion_end Default
- assert "${#lines[@]}" -eq 2 "$* $cmd: Suggestions are in the output"
+ _check_no_suggestions
fi
;;
@@ -205,16 +221,7 @@ function check_shell_completion() {
if [[ ! ${args##* } =~ "..." ]]; then
run_completion "$@" $cmd "${extra_args[@]}" ""
_check_completion_end NoFileComp
- if [ ${#lines[@]} -gt 2 ]; then
- # checking for line count is not enough since we may include additional debug output
- # lines starting with [Debug] are allowed
- i=0
- length=$(( ${#lines[@]} - 2 ))
- while [[ i -lt length ]]; do
- assert "${lines[$i]:0:7}" == "[Debug]" "Suggestions are in the output"
- i=$(( i + 1 ))
- done
- fi
+ _check_no_suggestions
fi
done
@@ -231,6 +238,24 @@ function _check_completion_end() {
is "${lines[-1]}" "Completion ended with directive: ShellCompDirective$1" "Completion has wrong ShellCompDirective set"
}
+# Check that there are no suggestions in the output.
+# We could only check stdout and not stderr but this is not possible with bats.
+# By default we always have two extra lines at the end for the ShellCompDirective.
+# Then we could also have other extra lines for debugging, they will always start
+# with [Debug], e.g. `[Debug] [Error] no container with name or ID "t12" found: no such container`.
+function _check_no_suggestions() {
+ if [ ${#lines[@]} -gt 2 ]; then
+ # Checking for line count is not enough since we may include additional debug output.
+ # Lines starting with [Debug] are allowed.
+ local i=0
+ length=$((${#lines[@]} - 2))
+ while [[ i -lt length ]]; do
+ assert "${lines[$i]:0:7}" == "[Debug]" "Unexpected non-Debug output line: ${lines[$i]}"
+ i=$((i + 1))
+ done
+ fi
+}
+
@test "podman shell completion test" {
@@ -280,11 +305,6 @@ function _check_completion_end() {
# create secret
run_podman secret create $random_secret_name $secret_file
- # $PODMAN may be a space-separated string, e.g. if we include a --url.
- local -a podman_as_array=($PODMAN)
- # __completeNoDesc must be the first arg if we running the completion cmd
- PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}"
-
# Called with no args -- start with 'podman --help'. check_shell_completion() will
# recurse for any subcommands.
check_shell_completion
@@ -316,3 +336,51 @@ function _check_completion_end() {
done <<<"$output"
}
+
+@test "podman shell completion for paths in container/image" {
+ skip_if_remote "mounting via remote does not work"
+ for cmd in create run; do
+ run_completion $cmd $IMAGE ""
+ assert "$output" =~ ".*^/etc/\$.*" "etc directory suggested (cmd: podman $cmd)"
+ assert "$output" =~ ".*^/home/\$.*" "home directory suggested (cmd: podman $cmd)"
+ assert "$output" =~ ".*^/root/\$.*" "root directory suggested (cmd: podman $cmd)"
+
+ # check completion for subdirectory
+ run_completion $cmd $IMAGE "/etc"
+ # It should be safe to assume the os-release file always exists in $IMAGE
+ assert "$output" =~ ".*^/etc/os-release\$.*" "/etc files suggested (cmd: podman $cmd /etc)"
+ # check completion for partial file name
+ run_completion $cmd $IMAGE "/etc/os-"
+ assert "$output" =~ ".*^/etc/os-release\$.*" "/etc files suggested (cmd: podman $cmd /etc/os-)"
+
+ # check completion with relative path components
+ # It is important the we will still use the image root and not escape to the host
+ run_completion $cmd $IMAGE "../../"
+ assert "$output" =~ ".*^../../etc/\$.*" "relative etc directory suggested (cmd: podman $cmd ../../)"
+ assert "$output" =~ ".*^../../home/\$.*" "relative home directory suggested (cmd: podman $cmd ../../)"
+ done
+
+ random_name=$(random_string 30)
+ random_file=$(random_string 30)
+ run_podman run --name $random_name $IMAGE sh -c "touch /tmp/$random_file && touch /tmp/${random_file}2 && mkdir /emptydir"
+
+ # check completion for podman cp
+ run_completion cp ""
+ assert "$output" =~ ".*^$random_name\:\$.*" "podman cp suggest container names"
+
+ run_completion cp "$random_name:"
+ assert "$output" =~ ".*^$random_name\:/etc/\$.*" "podman cp suggest paths in container"
+
+ run_completion cp "$random_name:/tmp"
+ assert "$output" =~ ".*^$random_name\:/tmp/$random_file\$.*" "podman cp suggest custom file in container"
+
+ run_completion cp "$random_name:/tmp/$random_file"
+ assert "$output" =~ ".*^$random_name\:/tmp/$random_file\$.*" "podman cp suggest /tmp/$random_file file in container"
+ assert "$output" =~ ".*^$random_name\:/tmp/${random_file}2\$.*" "podman cp suggest /tmp/${random_file}2 file in container"
+
+ run_completion cp "$random_name:/emptydir"
+ assert "$output" =~ ".*^$random_name\:/emptydir/\$.*ShellCompDirectiveNoSpace" "podman cp suggest empty dir with no space directive (:2)"
+
+ # cleanup container
+ run_podman rm $random_name
+}
diff --git a/test/system/build-testimage b/test/system/build-testimage
index eb5849b5e..a0d831abb 100755
--- a/test/system/build-testimage
+++ b/test/system/build-testimage
@@ -12,8 +12,8 @@
# still need a fedora image for that.
#
-# Buildah binary
-BUILDAH=${BUILDAH:-buildah}
+# Podman binary to use
+PODMAN=${PODMAN:-$(pwd)/bin/podman}
# Tag for this new image
YMD=$(date +%Y%m%d)
@@ -25,7 +25,8 @@ if [ -z "$create_script" ]; then
fi
# Creation timestamp, Zulu time
-create_time_z=$(env TZ=UTC date +'%Y-%m-%dT%H:%M:%SZ')
+create_time_t=$(date +%s)
+create_time_z=$(env TZ=UTC date --date=@$create_time_t +'%Y-%m-%dT%H:%M:%SZ')
set -ex
@@ -60,19 +61,33 @@ chmod 755 pause
# alpine because it's small and light and reliable
# - check for updates @ https://hub.docker.com/_/alpine
# busybox-extras provides httpd needed in 500-networking.bats
-cat >Containerfile <<EOF
+#
+# Two Containerfiles, because we have to do the image build in two parts,
+# which I think are easier to describe in reverse order:
+# 2) The second build has to be run with --timestamp=CONSTANT, otherwise
+# the Created test in 110-history.bats may fail (#14456); but
+# 1) the timestamp of the testimage-id file must be preserved (see above),
+# and 'build --timestamp' clobbers all file timestamps.
+#
+cat >Containerfile1 <<EOF
ARG REPO=please-override-repo
-FROM docker.io/\${REPO}/alpine:3.13.5
+FROM docker.io/\${REPO}/alpine:3.16.0
RUN apk add busybox-extras
ADD testimage-id pause /home/podman/
+EOF
+
+cat >Containerfile2 <<EOF
+FROM localhost/interim-image:latest
LABEL created_by=$create_script
LABEL created_at=$create_time_z
WORKDIR /home/podman
CMD ["/bin/echo", "This container is intended for podman CI testing"]
EOF
-# --squash-all : needed by 'tree' test in 070-build.bats
-podman rmi -f testimage &> /dev/null || true
+# Start from scratch
+testimg_base=quay.io/libpod/testimage
+testimg=${testimg_base}:$YMD
+$PODMAN rmi -f $testimg &> /dev/null || true
# There should always be a testimage tagged ':0000000<X>' (eight digits,
# zero-padded sequence ID) in the same location; this is used by tests
@@ -80,7 +95,7 @@ podman rmi -f testimage &> /dev/null || true
# if ever need to change, nor in fact does it even have to be a copy of
# this testimage since all we use it for is 'true'.
# However, it does need to be multiarch :-(
-zerotag_latest=$(skopeo list-tags docker://quay.io/libpod/testimage |\
+zerotag_latest=$(skopeo list-tags docker://${testimg_base} |\
jq -r '.Tags[]' |\
sort --version-sort |\
grep '^000' |\
@@ -88,12 +103,9 @@ zerotag_latest=$(skopeo list-tags docker://quay.io/libpod/testimage |\
zerotag_next=$(printf "%08d" $((zerotag_latest + 1)))
# We don't always need to push the :00xx image, but build it anyway.
-zeroimg=quay.io/libpod/testimage:${zerotag_next}
-buildah manifest create $zeroimg
+zeroimg=${testimg_base}:${zerotag_next}
+$PODMAN manifest create $zeroimg
-# We need to use buildah because (as of 2021-02-23) only buildah has --manifest
-# and because Dan says arch emulation is not currently working on podman
-# (no further details).
# Arch emulation on Fedora requires the qemu-user-static package.
for arch in amd64 arm64 ppc64le s390x;do
# docker.io repo is usually the same name as the desired arch; except
@@ -104,16 +116,32 @@ for arch in amd64 arm64 ppc64le s390x;do
repo="${repo}v8"
fi
- ${BUILDAH} bud \
- --arch=$arch \
- --build-arg REPO=$repo \
- --manifest=testimage \
- --squash \
- .
+ # First build defines REPO, but does not have --timestamp
+ $PODMAN build \
+ --arch=$arch \
+ --build-arg REPO=$repo \
+ --squash-all \
+ --file Containerfile1 \
+ -t interim-image \
+ .
+
+ # Second build forces --timestamp, and adds to manifest. Unfortunately
+ # we can't use --squash-all with --timestamp: *all* timestamps get
+ # clobbered. This is not fixable (#14536).
+ $PODMAN build \
+ --arch=$arch \
+ --timestamp=$create_time_t \
+ --manifest=$testimg \
+ --squash \
+ --file Containerfile2 \
+ .
+
+ # No longer need the interim image
+ $PODMAN rmi interim-image
# The zero-tag image
- ${BUILDAH} pull --arch $arch docker.io/$repo/busybox:1.33.1
- ${BUILDAH} manifest add $zeroimg docker.io/$repo/busybox:1.33.1
+ $PODMAN pull --arch $arch docker.io/$repo/busybox:1.34.1
+ $PODMAN manifest add $zeroimg docker.io/$repo/busybox:1.34.1
done
# Clean up
@@ -121,14 +149,12 @@ cd /tmp
rm -rf $tmpdir
# Tag image and push (all arches) to quay.
-remote_tag=quay.io/libpod/testimage:$YMD
-podman tag testimage ${remote_tag}
cat <<EOF
If you're happy with these images, run:
- ${BUILDAH} manifest push --all ${remote_tag} docker://${remote_tag}
- ${BUILDAH} manifest push --all ${zeroimg} docker://${zeroimg}
+ podman manifest push --all ${testimg} docker://${testimg}
+ podman manifest push --all ${zeroimg} docker://${zeroimg}
(You do not always need to push the :0000 image)
diff --git a/test/system/helpers.bash b/test/system/helpers.bash
index 6868f2691..ceac48036 100644
--- a/test/system/helpers.bash
+++ b/test/system/helpers.bash
@@ -7,14 +7,14 @@ PODMAN=${PODMAN:-podman}
PODMAN_TEST_IMAGE_REGISTRY=${PODMAN_TEST_IMAGE_REGISTRY:-"quay.io"}
PODMAN_TEST_IMAGE_USER=${PODMAN_TEST_IMAGE_USER:-"libpod"}
PODMAN_TEST_IMAGE_NAME=${PODMAN_TEST_IMAGE_NAME:-"testimage"}
-PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20210610"}
+PODMAN_TEST_IMAGE_TAG=${PODMAN_TEST_IMAGE_TAG:-"20220615"}
PODMAN_TEST_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_TEST_IMAGE_TAG"
PODMAN_TEST_IMAGE_ID=
# Remote image that we *DO NOT* fetch or keep by default; used for testing pull
# This has changed in 2021, from 0 through 3, various iterations of getting
# multiarch to work. It should change only very rarely.
-PODMAN_NONLOCAL_IMAGE_TAG=${PODMAN_NONLOCAL_IMAGE_TAG:-"00000003"}
+PODMAN_NONLOCAL_IMAGE_TAG=${PODMAN_NONLOCAL_IMAGE_TAG:-"00000004"}
PODMAN_NONLOCAL_IMAGE_FQN="$PODMAN_TEST_IMAGE_REGISTRY/$PODMAN_TEST_IMAGE_USER/$PODMAN_TEST_IMAGE_NAME:$PODMAN_NONLOCAL_IMAGE_TAG"
# Because who wants to spell that out each time?
@@ -284,7 +284,7 @@ function random_free_port() {
local port
for port in $(shuf -i ${range}); do
- if ! { exec {unused_fd}<> /dev/tcp/127.0.0.1/$port; } &>/dev/null; then
+ if port_is_free $port; then
echo $port
return
fi
@@ -293,6 +293,37 @@ function random_free_port() {
die "Could not find open port in range $range"
}
+function random_free_port_range() {
+ local size=${1?Usage: random_free_port_range SIZE (as in, number of ports)}
+
+ local maxtries=10
+ while [[ $maxtries -gt 0 ]]; do
+ local firstport=$(random_free_port)
+ local lastport=
+ for i in $(seq 1 $((size - 1))); do
+ lastport=$((firstport + i))
+ if ! port_is_free $lastport; then
+ echo "# port $lastport is in use; trying another." >&3
+ lastport=
+ break
+ fi
+ done
+ if [[ -n "$lastport" ]]; then
+ echo "$firstport-$lastport"
+ return
+ fi
+
+ maxtries=$((maxtries - 1))
+ done
+
+ die "Could not find free port range with size $size"
+}
+
+function port_is_free() {
+ local port=${1?Usage: port_is_free PORT}
+ ! { exec {unused_fd}<> /dev/tcp/127.0.0.1/$port; } &>/dev/null
+}
+
###################
# wait_for_port # Returns once port is available on host
###################
@@ -397,25 +428,25 @@ function _ensure_pod_state() {
for i in {0..5}; do
run_podman pod inspect $1 --format "{{.State}}"
if [[ $output == "$2" ]]; then
- break
+ return
fi
sleep 0.5
done
- is "$output" "$2" "unexpected pod state"
+ die "Timed out waiting for pod $1 to enter state $2"
}
# Wait for the container's (1st arg) running state (2nd arg)
function _ensure_container_running() {
- for i in {0..5}; do
+ for i in {0..20}; do
run_podman container inspect $1 --format "{{.State.Running}}"
if [[ $output == "$2" ]]; then
- break
+ return
fi
sleep 0.5
done
- is "$output" "$2" "unexpected pod state"
+ die "Timed out waiting for container $1 to enter state running=$2"
}
###########################
diff --git a/test/system/helpers.systemd.bash b/test/system/helpers.systemd.bash
index 4bde912a4..d9abc087d 100644
--- a/test/system/helpers.systemd.bash
+++ b/test/system/helpers.systemd.bash
@@ -28,3 +28,7 @@ systemctl() {
journalctl() {
command journalctl $_DASHUSER "$@"
}
+
+systemd-run() {
+ command systemd-run $_DASHUSER "$@";
+}
diff --git a/test/testvol/Containerfile b/test/testvol/Containerfile
new file mode 100644
index 000000000..32448f5a9
--- /dev/null
+++ b/test/testvol/Containerfile
@@ -0,0 +1,9 @@
+FROM docker.io/library/golang:1.18-alpine AS build-img
+COPY ./ /go/src/github.com/containers/podman/
+WORKDIR /go/src/github.com/containers/podman
+RUN GO111MODULE=off go build -o /testvol ./test/testvol
+
+FROM alpine
+COPY --from=build-img /testvol /usr/local/bin
+WORKDIR /
+ENTRYPOINT ["/usr/local/bin/testvol", "serve"]
diff --git a/test/testvol/create.go b/test/testvol/create.go
new file mode 100644
index 000000000..d29300f0b
--- /dev/null
+++ b/test/testvol/create.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ pluginapi "github.com/docker/go-plugins-helpers/volume"
+ "github.com/spf13/cobra"
+)
+
+var createCmd = &cobra.Command{
+ Use: "create NAME",
+ Short: "create a volume",
+ Long: `Create a volume in the volume plugin listening on --sock-name`,
+ Args: cobra.ExactArgs(1),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return createVol(config.sockName, args[0])
+ },
+}
+
+func createVol(sockName, volName string) error {
+ plugin, err := getPlugin(sockName)
+ if err != nil {
+ return err
+ }
+ createReq := new(pluginapi.CreateRequest)
+ createReq.Name = volName
+ return plugin.CreateVolume(createReq)
+}
diff --git a/test/testvol/list.go b/test/testvol/list.go
new file mode 100644
index 000000000..fea615a70
--- /dev/null
+++ b/test/testvol/list.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+ "fmt"
+
+ "github.com/spf13/cobra"
+)
+
+var listCmd = &cobra.Command{
+ Use: "list",
+ Short: "list all volumes",
+ Long: `List all volumes from the volume plugin listening on --sock-name`,
+ Args: cobra.NoArgs,
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return listVol(config.sockName)
+ },
+}
+
+func listVol(sockName string) error {
+ plugin, err := getPlugin(sockName)
+ if err != nil {
+ return err
+ }
+ vols, err := plugin.ListVolumes()
+ if err != nil {
+ return err
+ }
+ for _, vol := range vols {
+ fmt.Println(vol.Name)
+ }
+ return nil
+}
diff --git a/test/testvol/main.go b/test/testvol/main.go
index 30ab365b3..dd4ba642d 100644
--- a/test/testvol/main.go
+++ b/test/testvol/main.go
@@ -1,6 +1,7 @@
package main
import (
+ "fmt"
"io/ioutil"
"os"
"path/filepath"
@@ -8,19 +9,25 @@ import (
"time"
"github.com/docker/go-plugins-helpers/volume"
- "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{
- Use: "testvol",
- Short: "testvol - volume plugin for Podman",
+ Use: "testvol",
+ Short: "testvol - volume plugin for Podman testing",
+ PersistentPreRunE: before,
+ SilenceUsage: true,
+}
+
+var serveCmd = &cobra.Command{
+ Use: "serve",
+ Short: "serve the volume plugin on the unix socket",
Long: `Creates simple directory volumes using the Volume Plugin API for testing volume plugin functionality`,
+ Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
return startServer(config.sockName)
},
- PersistentPreRunE: before,
}
// Configuration for the volume plugin
@@ -37,9 +44,12 @@ var config = cliConfig{
}
func init() {
- rootCmd.Flags().StringVar(&config.sockName, "sock-name", config.sockName, "Name of unix socket for plugin")
- rootCmd.Flags().StringVar(&config.path, "path", "", "Path to initialize state and mount points")
+ rootCmd.PersistentFlags().StringVar(&config.sockName, "sock-name", config.sockName, "Name of unix socket for plugin")
rootCmd.PersistentFlags().StringVar(&config.logLevel, "log-level", config.logLevel, "Log messages including and over the specified level: debug, info, warn, error, fatal, panic")
+
+ serveCmd.Flags().StringVar(&config.path, "path", "", "Path to initialize state and mount points")
+
+ rootCmd.AddCommand(serveCmd, createCmd, removeCmd, listCmd)
}
func before(cmd *cobra.Command, args []string) error {
@@ -59,11 +69,8 @@ func before(cmd *cobra.Command, args []string) error {
func main() {
if err := rootCmd.Execute(); err != nil {
- logrus.Errorf("Running volume plugin: %v", err)
os.Exit(1)
}
-
- os.Exit(0)
}
// startServer runs the HTTP server and responds to requests
@@ -73,16 +80,16 @@ func startServer(socketPath string) error {
if config.path == "" {
path, err := ioutil.TempDir("", "test_volume_plugin")
if err != nil {
- return errors.Wrapf(err, "error getting directory for plugin")
+ return fmt.Errorf("error getting directory for plugin: %w", err)
}
config.path = path
} else {
pathStat, err := os.Stat(config.path)
if err != nil {
- return errors.Wrapf(err, "unable to access requested plugin state directory")
+ return fmt.Errorf("unable to access requested plugin state directory: %w", err)
}
if !pathStat.IsDir() {
- return errors.Errorf("cannot use %v as plugin state dir as it is not a directory", config.path)
+ return fmt.Errorf("cannot use %v as plugin state dir as it is not a directory", config.path)
}
}
@@ -91,7 +98,7 @@ func startServer(socketPath string) error {
server := volume.NewHandler(handle)
if err := server.ServeUnix(socketPath, 0); err != nil {
- return errors.Wrapf(err, "error starting server")
+ return fmt.Errorf("error starting server: %w", err)
}
return nil
}
@@ -140,7 +147,7 @@ func (d *DirDriver) Create(opts *volume.CreateRequest) error {
logrus.Infof("Hit Create() endpoint")
if _, exists := d.volumes[opts.Name]; exists {
- return errors.Errorf("volume with name %s already exists", opts.Name)
+ return fmt.Errorf("volume with name %s already exists", opts.Name)
}
newVol := new(dirVol)
@@ -154,7 +161,7 @@ func (d *DirDriver) Create(opts *volume.CreateRequest) error {
volPath := filepath.Join(d.volumesPath, opts.Name)
if err := os.Mkdir(volPath, 0755); err != nil {
- return errors.Wrapf(err, "error making volume directory")
+ return fmt.Errorf("error making volume directory: %w", err)
}
newVol.path = volPath
@@ -197,7 +204,7 @@ func (d *DirDriver) Get(req *volume.GetRequest) (*volume.GetResponse, error) {
vol, exists := d.volumes[req.Name]
if !exists {
logrus.Debugf("Did not find volume %s", req.Name)
- return nil, errors.Errorf("no volume with name %s found", req.Name)
+ return nil, fmt.Errorf("no volume with name %s found", req.Name)
}
logrus.Debugf("Found volume %s", req.Name)
@@ -221,19 +228,19 @@ func (d *DirDriver) Remove(req *volume.RemoveRequest) error {
vol, exists := d.volumes[req.Name]
if !exists {
logrus.Debugf("Did not find volume %s", req.Name)
- return errors.Errorf("no volume with name %s found", req.Name)
+ return fmt.Errorf("no volume with name %s found", req.Name)
}
logrus.Debugf("Found volume %s", req.Name)
if len(vol.mounts) > 0 {
logrus.Debugf("Cannot remove %s, is mounted", req.Name)
- return errors.Errorf("volume %s is mounted and cannot be removed", req.Name)
+ return fmt.Errorf("volume %s is mounted and cannot be removed", req.Name)
}
delete(d.volumes, req.Name)
if err := os.RemoveAll(vol.path); err != nil {
- return errors.Wrapf(err, "error removing mountpoint of volume %s", req.Name)
+ return fmt.Errorf("error removing mountpoint of volume %s: %w", req.Name, err)
}
logrus.Debugf("Removed volume %s", req.Name)
@@ -253,7 +260,7 @@ func (d *DirDriver) Path(req *volume.PathRequest) (*volume.PathResponse, error)
vol, exists := d.volumes[req.Name]
if !exists {
logrus.Debugf("Cannot locate volume %s", req.Name)
- return nil, errors.Errorf("no volume with name %s found", req.Name)
+ return nil, fmt.Errorf("no volume with name %s found", req.Name)
}
return &volume.PathResponse{
@@ -271,7 +278,7 @@ func (d *DirDriver) Mount(req *volume.MountRequest) (*volume.MountResponse, erro
vol, exists := d.volumes[req.Name]
if !exists {
logrus.Debugf("Cannot locate volume %s", req.Name)
- return nil, errors.Errorf("no volume with name %s found", req.Name)
+ return nil, fmt.Errorf("no volume with name %s found", req.Name)
}
vol.mounts[req.ID] = true
@@ -291,13 +298,13 @@ func (d *DirDriver) Unmount(req *volume.UnmountRequest) error {
vol, exists := d.volumes[req.Name]
if !exists {
logrus.Debugf("Cannot locate volume %s", req.Name)
- return errors.Errorf("no volume with name %s found", req.Name)
+ return fmt.Errorf("no volume with name %s found", req.Name)
}
mount := vol.mounts[req.ID]
if !mount {
logrus.Debugf("Volume %s is not mounted by %s", req.Name, req.ID)
- return errors.Errorf("volume %s is not mounted by %s", req.Name, req.ID)
+ return fmt.Errorf("volume %s is not mounted by %s", req.Name, req.ID)
}
delete(vol.mounts, req.ID)
diff --git a/test/testvol/remove.go b/test/testvol/remove.go
new file mode 100644
index 000000000..2839b0b50
--- /dev/null
+++ b/test/testvol/remove.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ pluginapi "github.com/docker/go-plugins-helpers/volume"
+ "github.com/spf13/cobra"
+)
+
+var removeCmd = &cobra.Command{
+ Use: "remove NAME",
+ Short: "remove a volume",
+ Long: `Remove a volume in the volume plugin listening on --sock-name`,
+ Args: cobra.ExactArgs(1),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ return removeVol(config.sockName, args[0])
+ },
+}
+
+func removeVol(sockName, volName string) error {
+ plugin, err := getPlugin(sockName)
+ if err != nil {
+ return err
+ }
+ removeReq := new(pluginapi.RemoveRequest)
+ removeReq.Name = volName
+ return plugin.RemoveVolume(removeReq)
+}
diff --git a/test/testvol/util.go b/test/testvol/util.go
new file mode 100644
index 000000000..b50bb3afb
--- /dev/null
+++ b/test/testvol/util.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/podman/v4/libpod/plugin"
+)
+
+const pluginSockDir = "/run/docker/plugins"
+
+func getSocketPath(pathOrName string) string {
+ if filepath.IsAbs(pathOrName) {
+ return pathOrName
+ }
+
+ // only a name join it with the default path
+ return filepath.Join(pluginSockDir, pathOrName+".sock")
+}
+
+func getPluginName(pathOrName string) string {
+ return strings.TrimSuffix(filepath.Base(pathOrName), ".sock")
+}
+
+func getPlugin(sockNameOrPath string) (*plugin.VolumePlugin, error) {
+ path := getSocketPath(sockNameOrPath)
+ name := getPluginName(sockNameOrPath)
+ return plugin.GetVolumePlugin(name, path, 0)
+}
diff --git a/test/tools/go.mod b/test/tools/go.mod
index 79d1fabe8..1c2867b99 100644
--- a/test/tools/go.mod
+++ b/test/tools/go.mod
@@ -5,5 +5,5 @@ go 1.16
require (
github.com/cpuguy83/go-md2man/v2 v2.0.2
github.com/vbatts/git-validation v1.1.0
- golang.org/x/tools v0.1.10
+ golang.org/x/tools v0.1.11
)
diff --git a/test/tools/go.sum b/test/tools/go.sum
index 9b466cbea..d17c3e645 100644
--- a/test/tools/go.sum
+++ b/test/tools/go.sum
@@ -20,8 +20,8 @@ github.com/vbatts/git-validation v1.1.0/go.mod h1:QyK3uQnRYWGt/5ezd8kcpwPrm6zn9t
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
-golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -41,9 +41,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20=
-golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
+golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
+golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/Makefile b/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/Makefile
index 97dd390e8..437fc9997 100644
--- a/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/Makefile
+++ b/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/Makefile
@@ -32,3 +32,4 @@ check-mod: # verifies that module changes for go.mod and go.sum are checked in
.PHONY: vendor
vendor: mod
@go mod vendor -v
+
diff --git a/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/go-md2man.1.md b/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/go-md2man.1.md
index ae722d078..16d1133aa 100644
--- a/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/go-md2man.1.md
+++ b/test/tools/vendor/github.com/cpuguy83/go-md2man/v2/go-md2man.1.md
@@ -20,3 +20,4 @@ go-md2man 1 "January 2015" go-md2man "User Manual"
# HISTORY
January 2015, Originally compiled by Brian Goff( cpuguy83@gmail.com )
+
diff --git a/test/tools/vendor/github.com/hashicorp/go-version/.travis.yml b/test/tools/vendor/github.com/hashicorp/go-version/.travis.yml
index b5f955d7e..01c5dc219 100644
--- a/test/tools/vendor/github.com/hashicorp/go-version/.travis.yml
+++ b/test/tools/vendor/github.com/hashicorp/go-version/.travis.yml
@@ -1,6 +1,6 @@
-language: go
+language: go
-go:
+go:
- 1.2
- 1.3
- 1.4
@@ -8,6 +8,6 @@ go:
- "1.10"
- 1.11
- 1.12
-
+
script:
- - go test
+ - go test
diff --git a/test/tools/vendor/github.com/hashicorp/go-version/LICENSE b/test/tools/vendor/github.com/hashicorp/go-version/LICENSE
index 82b4de97c..c33dcc7c9 100644
--- a/test/tools/vendor/github.com/hashicorp/go-version/LICENSE
+++ b/test/tools/vendor/github.com/hashicorp/go-version/LICENSE
@@ -351,3 +351,4 @@ Exhibit B - “Incompatible With Secondary Licenses” Notice
This Source Code Form is “Incompatible
With Secondary Licenses”, as defined by
the Mozilla Public License, v. 2.0.
+
diff --git a/test/tools/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md b/test/tools/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
index f8c9aa99e..949b77e30 100644
--- a/test/tools/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
+++ b/test/tools/vendor/github.com/konsorten/go-windows-terminal-sequences/README.md
@@ -9,7 +9,7 @@ See [Console Virtual Terminal Sequences](https://docs.microsoft.com/en-us/window
```go
import (
"syscall"
-
+
sequences "github.com/konsorten/go-windows-terminal-sequences"
)
diff --git a/test/tools/vendor/github.com/sirupsen/logrus/CHANGELOG.md b/test/tools/vendor/github.com/sirupsen/logrus/CHANGELOG.md
index 95ffc62ce..f62cbd24a 100644
--- a/test/tools/vendor/github.com/sirupsen/logrus/CHANGELOG.md
+++ b/test/tools/vendor/github.com/sirupsen/logrus/CHANGELOG.md
@@ -1,7 +1,7 @@
# 1.4.1
This new release introduces:
* Enhance TextFormatter to not print caller information when they are empty (#944)
- * Remove dependency on golang.org/x/crypto (#932, #943)
+ * Remove dependency on golang.org/x/crypto (#932, #943)
Fixes:
* Fix Entry.WithContext method to return a copy of the initial entry (#941)
diff --git a/test/tools/vendor/github.com/sirupsen/logrus/README.md b/test/tools/vendor/github.com/sirupsen/logrus/README.md
index 3bf033166..a4796eb07 100644
--- a/test/tools/vendor/github.com/sirupsen/logrus/README.md
+++ b/test/tools/vendor/github.com/sirupsen/logrus/README.md
@@ -84,7 +84,7 @@ time="2015-03-26T01:27:38-04:00" level=fatal method=github.com/sirupsen/arcticcr
```
Note that this does add measurable overhead - the cost will depend on the version of Go, but is
between 20 and 40% in recent tests with 1.6 and 1.7. You can validate this in your
-environment via benchmarks:
+environment via benchmarks:
```
go test -bench=.*CallerTracing
```
diff --git a/test/tools/vendor/github.com/sirupsen/logrus/appveyor.yml b/test/tools/vendor/github.com/sirupsen/logrus/appveyor.yml
index 1d4d64201..96c2ce15f 100644
--- a/test/tools/vendor/github.com/sirupsen/logrus/appveyor.yml
+++ b/test/tools/vendor/github.com/sirupsen/logrus/appveyor.yml
@@ -1,14 +1,14 @@
version: "{build}"
platform: x64
clone_folder: c:\gopath\src\github.com\sirupsen\logrus
-environment:
+environment:
GOPATH: c:\gopath
-branches:
+branches:
only:
- master
-install:
+install:
- set PATH=%GOPATH%\bin;c:\go\bin;%PATH%
- go version
-build_script:
+build_script:
- go get -t
- go test
diff --git a/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go b/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
index ff6ff7b99..3c4f43f91 100644
--- a/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
+++ b/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_bsd.go
@@ -10,3 +10,4 @@ func isTerminal(fd int) bool {
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
return err == nil
}
+
diff --git a/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_unix.go b/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
index 163c468d5..355dc966f 100644
--- a/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
+++ b/test/tools/vendor/github.com/sirupsen/logrus/terminal_check_unix.go
@@ -10,3 +10,4 @@ func isTerminal(fd int) bool {
_, err := unix.IoctlGetTermios(fd, ioctlReadTermios)
return err == nil
}
+
diff --git a/test/tools/vendor/github.com/vbatts/git-validation/README.md b/test/tools/vendor/github.com/vbatts/git-validation/README.md
index 000116e89..354276e02 100644
--- a/test/tools/vendor/github.com/vbatts/git-validation/README.md
+++ b/test/tools/vendor/github.com/vbatts/git-validation/README.md
@@ -73,7 +73,7 @@ vbatts@valse ~/src/vb/git-validation (master) $ git-validation -v
Here's a failure:
```console
-vbatts@valse ~/src/vb/git-validation (master) $ git-validation
+vbatts@valse ~/src/vb/git-validation (master) $ git-validation
* 49f51a8 "README: adding install and usage" ... FAIL
- FAIL - does not have a valid DCO
* d614ccf "*: run tests in a runner" ... PASS
@@ -103,3 +103,4 @@ See [`./rules/`](./rules/).
Feel free to contribute more.
Otherwise, by using `validate` package API directly, rules can be handed directly to the `validate.Runner`.
+
diff --git a/test/tools/vendor/golang.org/x/mod/module/module.go b/test/tools/vendor/golang.org/x/mod/module/module.go
index 355b5a456..c26d1d29e 100644
--- a/test/tools/vendor/golang.org/x/mod/module/module.go
+++ b/test/tools/vendor/golang.org/x/mod/module/module.go
@@ -15,7 +15,7 @@
// but additional checking functions, most notably Check, verify that
// a particular path, version pair is valid.
//
-// Escaped Paths
+// # Escaped Paths
//
// Module paths appear as substrings of file system paths
// (in the download cache) and of web server URLs in the proxy protocol.
@@ -55,7 +55,7 @@
// Import paths have never allowed exclamation marks, so there is no
// need to define how to escape a literal !.
//
-// Unicode Restrictions
+// # Unicode Restrictions
//
// Today, paths are disallowed from using Unicode.
//
@@ -102,9 +102,9 @@ import (
"strings"
"unicode"
"unicode/utf8"
+ "errors"
"golang.org/x/mod/semver"
- errors "golang.org/x/xerrors"
)
// A Version (for clients, a module.Version) is defined by a module path and version pair.
diff --git a/test/tools/vendor/golang.org/x/tools/cmd/goimports/doc.go b/test/tools/vendor/golang.org/x/tools/cmd/goimports/doc.go
index 5a5b9005f..18a3ad448 100644
--- a/test/tools/vendor/golang.org/x/tools/cmd/goimports/doc.go
+++ b/test/tools/vendor/golang.org/x/tools/cmd/goimports/doc.go
@@ -3,29 +3,33 @@
// license that can be found in the LICENSE file.
/*
-
Command goimports updates your Go import lines,
adding missing ones and removing unreferenced ones.
- $ go install golang.org/x/tools/cmd/goimports@latest
+ $ go install golang.org/x/tools/cmd/goimports@latest
In addition to fixing imports, goimports also formats
your code in the same style as gofmt so it can be used
as a replacement for your editor's gofmt-on-save hook.
For emacs, make sure you have the latest go-mode.el:
- https://github.com/dominikh/go-mode.el
+
+ https://github.com/dominikh/go-mode.el
+
Then in your .emacs file:
- (setq gofmt-command "goimports")
- (add-hook 'before-save-hook 'gofmt-before-save)
+
+ (setq gofmt-command "goimports")
+ (add-hook 'before-save-hook 'gofmt-before-save)
For vim, set "gofmt_command" to "goimports":
- https://golang.org/change/39c724dd7f252
- https://golang.org/wiki/IDEsAndTextEditorPlugins
- etc
+
+ https://golang.org/change/39c724dd7f252
+ https://golang.org/wiki/IDEsAndTextEditorPlugins
+ etc
For GoSublime, follow the steps described here:
- http://michaelwhatcott.com/gosublime-goimports/
+
+ http://michaelwhatcott.com/gosublime-goimports/
For other editors, you probably know what to do.
@@ -39,9 +43,8 @@ working and see what goimports is doing.
File bugs or feature requests at:
- https://golang.org/issues/new?title=x/tools/cmd/goimports:+
+ https://golang.org/issues/new?title=x/tools/cmd/goimports:+
Happy hacking!
-
*/
package main // import "golang.org/x/tools/cmd/goimports"
diff --git a/test/tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go b/test/tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go
index a5c6d6d4f..9fa5aa192 100644
--- a/test/tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go
+++ b/test/tools/vendor/golang.org/x/tools/go/ast/astutil/enclosing.go
@@ -22,9 +22,9 @@ import (
// additional whitespace abutting a node to be enclosed by it.
// In this example:
//
-// z := x + y // add them
-// <-A->
-// <----B----->
+// z := x + y // add them
+// <-A->
+// <----B----->
//
// the ast.BinaryExpr(+) node is considered to enclose interval B
// even though its [Pos()..End()) is actually only interval A.
@@ -43,10 +43,10 @@ import (
// interior whitespace of path[0].
// In this example:
//
-// z := x + y // add them
-// <--C--> <---E-->
-// ^
-// D
+// z := x + y // add them
+// <--C--> <---E-->
+// ^
+// D
//
// intervals C, D and E are inexact. C is contained by the
// z-assignment statement, because it spans three of its children (:=,
@@ -54,12 +54,11 @@ import (
// interior whitespace of the assignment. E is considered interior
// whitespace of the BlockStmt containing the assignment.
//
-// Precondition: [start, end) both lie within the same file as root.
-// TODO(adonovan): return (nil, false) in this case and remove precond.
-// Requires FileSet; see loader.tokenFileContainsPos.
-//
-// Postcondition: path is never nil; it always contains at least 'root'.
-//
+// The resulting path is never empty; it always contains at least the
+// 'root' *ast.File. Ideally PathEnclosingInterval would reject
+// intervals that lie wholly or partially outside the range of the
+// file, but unfortunately ast.File records only the token.Pos of
+// the 'package' keyword, but not of the start of the file itself.
func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Node, exact bool) {
// fmt.Printf("EnclosingInterval %d %d\n", start, end) // debugging
@@ -135,6 +134,7 @@ func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Nod
return false // inexact: overlaps multiple children
}
+ // Ensure [start,end) is nondecreasing.
if start > end {
start, end = end, start
}
@@ -162,7 +162,6 @@ func PathEnclosingInterval(root *ast.File, start, end token.Pos) (path []ast.Nod
// tokenNode is a dummy implementation of ast.Node for a single token.
// They are used transiently by PathEnclosingInterval but never escape
// this package.
-//
type tokenNode struct {
pos token.Pos
end token.Pos
@@ -183,7 +182,6 @@ func tok(pos token.Pos, len int) ast.Node {
// childrenOf returns the direct non-nil children of ast.Node n.
// It may include fake ast.Node implementations for bare tokens.
// it is not safe to call (e.g.) ast.Walk on such nodes.
-//
func childrenOf(n ast.Node) []ast.Node {
var children []ast.Node
@@ -488,7 +486,6 @@ func (sl byPos) Swap(i, j int) {
// TODO(adonovan): in some cases (e.g. Field, FieldList, Ident,
// StarExpr) we could be much more specific given the path to the AST
// root. Perhaps we should do that.
-//
func NodeDescription(n ast.Node) string {
switch n := n.(type) {
case *ast.ArrayType:
diff --git a/test/tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go b/test/tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go
index 2087ceec9..18d1adb05 100644
--- a/test/tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go
+++ b/test/tools/vendor/golang.org/x/tools/go/ast/astutil/imports.go
@@ -22,8 +22,11 @@ func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) {
// If name is not empty, it is used to rename the import.
//
// For example, calling
+//
// AddNamedImport(fset, f, "pathpkg", "path")
+//
// adds
+//
// import pathpkg "path"
func AddNamedImport(fset *token.FileSet, f *ast.File, name, path string) (added bool) {
if imports(f, name, path) {
@@ -270,8 +273,8 @@ func DeleteNamedImport(fset *token.FileSet, f *ast.File, name, path string) (del
}
if j > 0 {
lastImpspec := gen.Specs[j-1].(*ast.ImportSpec)
- lastLine := fset.Position(lastImpspec.Path.ValuePos).Line
- line := fset.Position(impspec.Path.ValuePos).Line
+ lastLine := fset.PositionFor(lastImpspec.Path.ValuePos, false).Line
+ line := fset.PositionFor(impspec.Path.ValuePos, false).Line
// We deleted an entry but now there may be
// a blank line-sized hole where the import was.
diff --git a/test/tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go b/test/tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go
index 6d9ca23e2..f430b21b9 100644
--- a/test/tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go
+++ b/test/tools/vendor/golang.org/x/tools/go/ast/astutil/rewrite.go
@@ -41,7 +41,6 @@ type ApplyFunc func(*Cursor) bool
// Children are traversed in the order in which they appear in the
// respective node's struct definition. A package's files are
// traversed in the filenames' alphabetical order.
-//
func Apply(root ast.Node, pre, post ApplyFunc) (result ast.Node) {
parent := &struct{ ast.Node }{root}
defer func() {
@@ -65,8 +64,8 @@ var abort = new(int) // singleton, to signal termination of Apply
// c.Parent(), and f is the field identifier with name c.Name(),
// the following invariants hold:
//
-// p.f == c.Node() if c.Index() < 0
-// p.f[c.Index()] == c.Node() if c.Index() >= 0
+// p.f == c.Node() if c.Index() < 0
+// p.f[c.Index()] == c.Node() if c.Index() >= 0
//
// The methods Replace, Delete, InsertBefore, and InsertAfter
// can be used to change the AST without disrupting Apply.
@@ -294,6 +293,9 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.
a.apply(n, "Fields", nil, n.Fields)
case *ast.FuncType:
+ if tparams := typeparams.ForFuncType(n); tparams != nil {
+ a.apply(n, "TypeParams", nil, tparams)
+ }
a.apply(n, "Params", nil, n.Params)
a.apply(n, "Results", nil, n.Results)
@@ -406,6 +408,9 @@ func (a *application) apply(parent ast.Node, name string, iter *iterator, n ast.
case *ast.TypeSpec:
a.apply(n, "Doc", nil, n.Doc)
a.apply(n, "Name", nil, n.Name)
+ if tparams := typeparams.ForTypeSpec(n); tparams != nil {
+ a.apply(n, "TypeParams", nil, tparams)
+ }
a.apply(n, "Type", nil, n.Type)
a.apply(n, "Comment", nil, n.Comment)
diff --git a/test/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go b/test/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go
index 9887f7e7a..798fe599b 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/fastwalk/fastwalk.go
@@ -40,12 +40,12 @@ var ErrSkipFiles = errors.New("fastwalk: skip remaining files in directory")
// If fastWalk returns filepath.SkipDir, the directory is skipped.
//
// Unlike filepath.Walk:
-// * file stat calls must be done by the user.
+// - file stat calls must be done by the user.
// The only provided metadata is the file type, which does not include
// any permission bits.
-// * multiple goroutines stat the filesystem concurrently. The provided
+// - multiple goroutines stat the filesystem concurrently. The provided
// walkFn must be safe for concurrent use.
-// * fastWalk can follow symlinks if walkFn returns the TraverseLink
+// - fastWalk can follow symlinks if walkFn returns the TraverseLink
// sentinel error. It is the walkFn's responsibility to prevent
// fastWalk from going into symlink cycles.
func Walk(root string, walkFn func(path string, typ os.FileMode) error) error {
diff --git a/test/tools/vendor/golang.org/x/tools/internal/gocommand/invoke.go b/test/tools/vendor/golang.org/x/tools/internal/gocommand/invoke.go
index f75336834..67256dc39 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/gocommand/invoke.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/gocommand/invoke.go
@@ -264,8 +264,10 @@ func cmdDebugStr(cmd *exec.Cmd) string {
env := make(map[string]string)
for _, kv := range cmd.Env {
split := strings.SplitN(kv, "=", 2)
- k, v := split[0], split[1]
- env[k] = v
+ if len(split) == 2 {
+ k, v := split[0], split[1]
+ env[k] = v
+ }
}
var args []string
diff --git a/test/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go b/test/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
index 925ff5356..168405322 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/gopathwalk/walk.go
@@ -175,8 +175,8 @@ func (w *walker) shouldSkipDir(fi os.FileInfo, dir string) bool {
// walk walks through the given path.
func (w *walker) walk(path string, typ os.FileMode) error {
- dir := filepath.Dir(path)
if typ.IsRegular() {
+ dir := filepath.Dir(path)
if dir == w.root.Path && (w.root.Type == RootGOROOT || w.root.Type == RootGOPATH) {
// Doesn't make sense to have regular files
// directly in your $GOPATH/src or $GOROOT/src.
@@ -209,12 +209,7 @@ func (w *walker) walk(path string, typ os.FileMode) error {
// Emacs noise.
return nil
}
- fi, err := os.Lstat(path)
- if err != nil {
- // Just ignore it.
- return nil
- }
- if w.shouldTraverse(dir, fi) {
+ if w.shouldTraverse(path) {
return fastwalk.ErrTraverseLink
}
}
@@ -224,13 +219,8 @@ func (w *walker) walk(path string, typ os.FileMode) error {
// shouldTraverse reports whether the symlink fi, found in dir,
// should be followed. It makes sure symlinks were never visited
// before to avoid symlink loops.
-func (w *walker) shouldTraverse(dir string, fi os.FileInfo) bool {
- path := filepath.Join(dir, fi.Name())
- target, err := filepath.EvalSymlinks(path)
- if err != nil {
- return false
- }
- ts, err := os.Stat(target)
+func (w *walker) shouldTraverse(path string) bool {
+ ts, err := os.Stat(path)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return false
@@ -238,7 +228,7 @@ func (w *walker) shouldTraverse(dir string, fi os.FileInfo) bool {
if !ts.IsDir() {
return false
}
- if w.shouldSkipDir(ts, dir) {
+ if w.shouldSkipDir(ts, filepath.Dir(path)) {
return false
}
// Check for symlink loops by statting each directory component
diff --git a/test/tools/vendor/golang.org/x/tools/internal/imports/imports.go b/test/tools/vendor/golang.org/x/tools/internal/imports/imports.go
index 25973989e..95a88383a 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/imports/imports.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/imports/imports.go
@@ -103,12 +103,17 @@ func ApplyFixes(fixes []*ImportFix, filename string, src []byte, opt *Options, e
return formatFile(fileSet, file, src, nil, opt)
}
-func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) {
- mergeImports(fileSet, file)
- sortImports(opt.LocalPrefix, fileSet, file)
- imps := astutil.Imports(fileSet, file)
+// formatFile formats the file syntax tree.
+// It may mutate the token.FileSet.
+//
+// If an adjust function is provided, it is called after formatting
+// with the original source (formatFile's src parameter) and the
+// formatted file, and returns the postpocessed result.
+func formatFile(fset *token.FileSet, file *ast.File, src []byte, adjust func(orig []byte, src []byte) []byte, opt *Options) ([]byte, error) {
+ mergeImports(file)
+ sortImports(opt.LocalPrefix, fset.File(file.Pos()), file)
var spacesBefore []string // import paths we need spaces before
- for _, impSection := range imps {
+ for _, impSection := range astutil.Imports(fset, file) {
// Within each block of contiguous imports, see if any
// import lines are in different group numbers. If so,
// we'll need to put a space between them so it's
@@ -132,7 +137,7 @@ func formatFile(fileSet *token.FileSet, file *ast.File, src []byte, adjust func(
printConfig := &printer.Config{Mode: printerMode, Tabwidth: opt.TabWidth}
var buf bytes.Buffer
- err := printConfig.Fprint(&buf, fileSet, file)
+ err := printConfig.Fprint(&buf, fset, file)
if err != nil {
return nil, err
}
@@ -276,11 +281,11 @@ func cutSpace(b []byte) (before, middle, after []byte) {
}
// matchSpace reformats src to use the same space context as orig.
-// 1) If orig begins with blank lines, matchSpace inserts them at the beginning of src.
-// 2) matchSpace copies the indentation of the first non-blank line in orig
-// to every non-blank line in src.
-// 3) matchSpace copies the trailing space from orig and uses it in place
-// of src's trailing space.
+// 1. If orig begins with blank lines, matchSpace inserts them at the beginning of src.
+// 2. matchSpace copies the indentation of the first non-blank line in orig
+// to every non-blank line in src.
+// 3. matchSpace copies the trailing space from orig and uses it in place
+// of src's trailing space.
func matchSpace(orig []byte, src []byte) []byte {
before, _, after := cutSpace(orig)
i := bytes.LastIndex(before, []byte{'\n'})
diff --git a/test/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go b/test/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go
index dc52372e4..85144db1d 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/imports/sortimports.go
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// Hacked up copy of go/ast/import.go
+// Modified to use a single token.File in preference to a FileSet.
package imports
@@ -16,7 +17,9 @@ import (
// sortImports sorts runs of consecutive import lines in import blocks in f.
// It also removes duplicate imports when it is possible to do so without data loss.
-func sortImports(localPrefix string, fset *token.FileSet, f *ast.File) {
+//
+// It may mutate the token.File.
+func sortImports(localPrefix string, tokFile *token.File, f *ast.File) {
for i, d := range f.Decls {
d, ok := d.(*ast.GenDecl)
if !ok || d.Tok != token.IMPORT {
@@ -39,21 +42,21 @@ func sortImports(localPrefix string, fset *token.FileSet, f *ast.File) {
i := 0
specs := d.Specs[:0]
for j, s := range d.Specs {
- if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line {
+ if j > i && tokFile.Line(s.Pos()) > 1+tokFile.Line(d.Specs[j-1].End()) {
// j begins a new run. End this one.
- specs = append(specs, sortSpecs(localPrefix, fset, f, d.Specs[i:j])...)
+ specs = append(specs, sortSpecs(localPrefix, tokFile, f, d.Specs[i:j])...)
i = j
}
}
- specs = append(specs, sortSpecs(localPrefix, fset, f, d.Specs[i:])...)
+ specs = append(specs, sortSpecs(localPrefix, tokFile, f, d.Specs[i:])...)
d.Specs = specs
// Deduping can leave a blank line before the rparen; clean that up.
if len(d.Specs) > 0 {
lastSpec := d.Specs[len(d.Specs)-1]
- lastLine := fset.Position(lastSpec.Pos()).Line
- if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
- fset.File(d.Rparen).MergeLine(rParenLine - 1)
+ lastLine := tokFile.PositionFor(lastSpec.Pos(), false).Line
+ if rParenLine := tokFile.PositionFor(d.Rparen, false).Line; rParenLine > lastLine+1 {
+ tokFile.MergeLine(rParenLine - 1) // has side effects!
}
}
}
@@ -62,7 +65,7 @@ func sortImports(localPrefix string, fset *token.FileSet, f *ast.File) {
// mergeImports merges all the import declarations into the first one.
// Taken from golang.org/x/tools/ast/astutil.
// This does not adjust line numbers properly
-func mergeImports(fset *token.FileSet, f *ast.File) {
+func mergeImports(f *ast.File) {
if len(f.Decls) <= 1 {
return
}
@@ -144,7 +147,9 @@ type posSpan struct {
End token.Pos
}
-func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast.Spec) []ast.Spec {
+// sortSpecs sorts the import specs within each import decl.
+// It may mutate the token.File.
+func sortSpecs(localPrefix string, tokFile *token.File, f *ast.File, specs []ast.Spec) []ast.Spec {
// Can't short-circuit here even if specs are already sorted,
// since they might yet need deduplication.
// A lone import, however, may be safely ignored.
@@ -160,7 +165,7 @@ func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast
// Identify comments in this range.
// Any comment from pos[0].Start to the final line counts.
- lastLine := fset.Position(pos[len(pos)-1].End).Line
+ lastLine := tokFile.Line(pos[len(pos)-1].End)
cstart := len(f.Comments)
cend := len(f.Comments)
for i, g := range f.Comments {
@@ -170,7 +175,7 @@ func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast
if i < cstart {
cstart = i
}
- if fset.Position(g.End()).Line > lastLine {
+ if tokFile.Line(g.End()) > lastLine {
cend = i
break
}
@@ -203,7 +208,7 @@ func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast
deduped = append(deduped, s)
} else {
p := s.Pos()
- fset.File(p).MergeLine(fset.Position(p).Line)
+ tokFile.MergeLine(tokFile.Line(p)) // has side effects!
}
}
specs = deduped
@@ -234,21 +239,21 @@ func sortSpecs(localPrefix string, fset *token.FileSet, f *ast.File, specs []ast
// Fixup comments can insert blank lines, because import specs are on different lines.
// We remove those blank lines here by merging import spec to the first import spec line.
- firstSpecLine := fset.Position(specs[0].Pos()).Line
+ firstSpecLine := tokFile.Line(specs[0].Pos())
for _, s := range specs[1:] {
p := s.Pos()
- line := fset.File(p).Line(p)
+ line := tokFile.Line(p)
for previousLine := line - 1; previousLine >= firstSpecLine; {
// MergeLine can panic. Avoid the panic at the cost of not removing the blank line
// golang/go#50329
- if previousLine > 0 && previousLine < fset.File(p).LineCount() {
- fset.File(p).MergeLine(previousLine)
+ if previousLine > 0 && previousLine < tokFile.LineCount() {
+ tokFile.MergeLine(previousLine) // has side effects!
previousLine--
} else {
// try to gather some data to diagnose how this could happen
req := "Please report what the imports section of your go file looked like."
log.Printf("panic avoided: first:%d line:%d previous:%d max:%d. %s",
- firstSpecLine, line, previousLine, fset.File(p).LineCount(), req)
+ firstSpecLine, line, previousLine, tokFile.LineCount(), req)
}
}
}
diff --git a/test/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go b/test/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go
index 7de2be9b4..437fbb78d 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/imports/zstdlib.go
@@ -88,6 +88,7 @@ var stdlib = map[string][]string{
"ContainsAny",
"ContainsRune",
"Count",
+ "Cut",
"Equal",
"EqualFold",
"ErrTooLarge",
@@ -711,6 +712,11 @@ var stdlib = map[string][]string{
"ValueConverter",
"Valuer",
},
+ "debug/buildinfo": []string{
+ "BuildInfo",
+ "Read",
+ "ReadFile",
+ },
"debug/dwarf": []string{
"AddrType",
"ArrayType",
@@ -1944,6 +1950,7 @@ var stdlib = map[string][]string{
"R_PPC64_REL24_NOTOC",
"R_PPC64_REL32",
"R_PPC64_REL64",
+ "R_PPC64_RELATIVE",
"R_PPC64_SECTOFF_DS",
"R_PPC64_SECTOFF_LO_DS",
"R_PPC64_TLS",
@@ -2547,6 +2554,7 @@ var stdlib = map[string][]string{
"Symbol",
},
"debug/plan9obj": []string{
+ "ErrNoSymbols",
"File",
"FileHeader",
"Magic386",
@@ -2906,6 +2914,7 @@ var stdlib = map[string][]string{
"Importer",
"IncDecStmt",
"IndexExpr",
+ "IndexListExpr",
"Inspect",
"InterfaceType",
"IsExported",
@@ -3179,6 +3188,7 @@ var stdlib = map[string][]string{
"SUB",
"SUB_ASSIGN",
"SWITCH",
+ "TILDE",
"TYPE",
"Token",
"UnaryPrec",
@@ -3187,6 +3197,7 @@ var stdlib = map[string][]string{
"XOR_ASSIGN",
},
"go/types": []string{
+ "ArgumentError",
"Array",
"AssertableTo",
"AssignableTo",
@@ -3205,6 +3216,7 @@ var stdlib = map[string][]string{
"Complex64",
"Config",
"Const",
+ "Context",
"ConvertibleTo",
"DefPredeclaredTestFuncs",
"Default",
@@ -3224,6 +3236,8 @@ var stdlib = map[string][]string{
"ImporterFrom",
"Info",
"Initializer",
+ "Instance",
+ "Instantiate",
"Int",
"Int16",
"Int32",
@@ -3254,6 +3268,7 @@ var stdlib = map[string][]string{
"NewChan",
"NewChecker",
"NewConst",
+ "NewContext",
"NewField",
"NewFunc",
"NewInterface",
@@ -3268,10 +3283,14 @@ var stdlib = map[string][]string{
"NewPointer",
"NewScope",
"NewSignature",
+ "NewSignatureType",
"NewSlice",
"NewStruct",
+ "NewTerm",
"NewTuple",
"NewTypeName",
+ "NewTypeParam",
+ "NewUnion",
"NewVar",
"Nil",
"Object",
@@ -3296,11 +3315,15 @@ var stdlib = map[string][]string{
"StdSizes",
"String",
"Struct",
+ "Term",
"Tuple",
"Typ",
"Type",
"TypeAndValue",
+ "TypeList",
"TypeName",
+ "TypeParam",
+ "TypeParamList",
"TypeString",
"Uint",
"Uint16",
@@ -3308,6 +3331,7 @@ var stdlib = map[string][]string{
"Uint64",
"Uint8",
"Uintptr",
+ "Union",
"Universe",
"Unsafe",
"UnsafePointer",
@@ -4080,9 +4104,11 @@ var stdlib = map[string][]string{
"SRV",
"SplitHostPort",
"TCPAddr",
+ "TCPAddrFromAddrPort",
"TCPConn",
"TCPListener",
"UDPAddr",
+ "UDPAddrFromAddrPort",
"UDPConn",
"UnixAddr",
"UnixConn",
@@ -4142,6 +4168,7 @@ var stdlib = map[string][]string{
"ListenAndServe",
"ListenAndServeTLS",
"LocalAddrContextKey",
+ "MaxBytesHandler",
"MaxBytesReader",
"MethodConnect",
"MethodDelete",
@@ -4338,6 +4365,25 @@ var stdlib = map[string][]string{
"ParseDate",
"ReadMessage",
},
+ "net/netip": []string{
+ "Addr",
+ "AddrFrom16",
+ "AddrFrom4",
+ "AddrFromSlice",
+ "AddrPort",
+ "AddrPortFrom",
+ "IPv4Unspecified",
+ "IPv6LinkLocalAllNodes",
+ "IPv6Unspecified",
+ "MustParseAddr",
+ "MustParseAddrPort",
+ "MustParsePrefix",
+ "ParseAddr",
+ "ParseAddrPort",
+ "ParsePrefix",
+ "Prefix",
+ "PrefixFrom",
+ },
"net/rpc": []string{
"Accept",
"Call",
@@ -4641,6 +4687,8 @@ var stdlib = map[string][]string{
"Method",
"New",
"NewAt",
+ "Pointer",
+ "PointerTo",
"Ptr",
"PtrTo",
"RecvDir",
@@ -4819,9 +4867,11 @@ var stdlib = map[string][]string{
},
"runtime/debug": []string{
"BuildInfo",
+ "BuildSetting",
"FreeOSMemory",
"GCStats",
"Module",
+ "ParseBuildInfo",
"PrintStack",
"ReadBuildInfo",
"ReadGCStats",
@@ -4939,11 +4989,13 @@ var stdlib = map[string][]string{
},
"strings": []string{
"Builder",
+ "Clone",
"Compare",
"Contains",
"ContainsAny",
"ContainsRune",
"Count",
+ "Cut",
"EqualFold",
"Fields",
"FieldsFunc",
@@ -9793,6 +9845,7 @@ var stdlib = map[string][]string{
"Syscall18",
"Syscall6",
"Syscall9",
+ "SyscallN",
"Sysctl",
"SysctlUint32",
"Sysctlnode",
@@ -10202,7 +10255,6 @@ var stdlib = map[string][]string{
"Value",
"ValueError",
"ValueOf",
- "Wrapper",
},
"testing": []string{
"AllocsPerRun",
@@ -10213,9 +10265,11 @@ var stdlib = map[string][]string{
"CoverBlock",
"CoverMode",
"Coverage",
+ "F",
"Init",
"InternalBenchmark",
"InternalExample",
+ "InternalFuzzTarget",
"InternalTest",
"M",
"Main",
@@ -10313,9 +10367,11 @@ var stdlib = map[string][]string{
"ActionNode",
"BoolNode",
"BranchNode",
+ "BreakNode",
"ChainNode",
"CommandNode",
"CommentNode",
+ "ContinueNode",
"DotNode",
"FieldNode",
"IdentifierNode",
@@ -10329,9 +10385,11 @@ var stdlib = map[string][]string{
"Node",
"NodeAction",
"NodeBool",
+ "NodeBreak",
"NodeChain",
"NodeCommand",
"NodeComment",
+ "NodeContinue",
"NodeDot",
"NodeField",
"NodeIdentifier",
@@ -10727,6 +10785,7 @@ var stdlib = map[string][]string{
"IsSurrogate",
},
"unicode/utf8": []string{
+ "AppendRune",
"DecodeLastRune",
"DecodeLastRuneInString",
"DecodeRune",
diff --git a/test/tools/vendor/golang.org/x/tools/internal/typeparams/common.go b/test/tools/vendor/golang.org/x/tools/internal/typeparams/common.go
index ab6b30b83..25a1426d3 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/typeparams/common.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/typeparams/common.go
@@ -16,11 +16,10 @@
// Additionally, this package contains common utilities for working with the
// new generic constructs, to supplement the standard library APIs. Notably,
// the StructuralTerms API computes a minimal representation of the structural
-// restrictions on a type parameter. In the future, this API may be available
-// from go/types.
+// restrictions on a type parameter.
//
-// See the example/README.md for a more detailed guide on how to update tools
-// to support generics.
+// An external version of these APIs is available in the
+// golang.org/x/exp/typeparams module.
package typeparams
import (
@@ -121,15 +120,15 @@ func OriginMethod(fn *types.Func) *types.Func {
//
// For example, consider the following type declarations:
//
-// type Interface[T any] interface {
-// Accept(T)
-// }
+// type Interface[T any] interface {
+// Accept(T)
+// }
//
-// type Container[T any] struct {
-// Element T
-// }
+// type Container[T any] struct {
+// Element T
+// }
//
-// func (c Container[T]) Accept(t T) { c.Element = t }
+// func (c Container[T]) Accept(t T) { c.Element = t }
//
// In this case, GenericAssignableTo reports that instantiations of Container
// are assignable to the corresponding instantiation of Interface.
diff --git a/test/tools/vendor/golang.org/x/tools/internal/typeparams/coretype.go b/test/tools/vendor/golang.org/x/tools/internal/typeparams/coretype.go
new file mode 100644
index 000000000..993135ec9
--- /dev/null
+++ b/test/tools/vendor/golang.org/x/tools/internal/typeparams/coretype.go
@@ -0,0 +1,122 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typeparams
+
+import (
+ "go/types"
+)
+
+// CoreType returns the core type of T or nil if T does not have a core type.
+//
+// See https://go.dev/ref/spec#Core_types for the definition of a core type.
+func CoreType(T types.Type) types.Type {
+ U := T.Underlying()
+ if _, ok := U.(*types.Interface); !ok {
+ return U // for non-interface types,
+ }
+
+ terms, err := _NormalTerms(U)
+ if len(terms) == 0 || err != nil {
+ // len(terms) -> empty type set of interface.
+ // err != nil => U is invalid, exceeds complexity bounds, or has an empty type set.
+ return nil // no core type.
+ }
+
+ U = terms[0].Type().Underlying()
+ var identical int // i in [0,identical) => Identical(U, terms[i].Type().Underlying())
+ for identical = 1; identical < len(terms); identical++ {
+ if !types.Identical(U, terms[identical].Type().Underlying()) {
+ break
+ }
+ }
+
+ if identical == len(terms) {
+ // https://go.dev/ref/spec#Core_types
+ // "There is a single type U which is the underlying type of all types in the type set of T"
+ return U
+ }
+ ch, ok := U.(*types.Chan)
+ if !ok {
+ return nil // no core type as identical < len(terms) and U is not a channel.
+ }
+ // https://go.dev/ref/spec#Core_types
+ // "the type chan E if T contains only bidirectional channels, or the type chan<- E or
+ // <-chan E depending on the direction of the directional channels present."
+ for chans := identical; chans < len(terms); chans++ {
+ curr, ok := terms[chans].Type().Underlying().(*types.Chan)
+ if !ok {
+ return nil
+ }
+ if !types.Identical(ch.Elem(), curr.Elem()) {
+ return nil // channel elements are not identical.
+ }
+ if ch.Dir() == types.SendRecv {
+ // ch is bidirectional. We can safely always use curr's direction.
+ ch = curr
+ } else if curr.Dir() != types.SendRecv && ch.Dir() != curr.Dir() {
+ // ch and curr are not bidirectional and not the same direction.
+ return nil
+ }
+ }
+ return ch
+}
+
+// _NormalTerms returns a slice of terms representing the normalized structural
+// type restrictions of a type, if any.
+//
+// For all types other than *types.TypeParam, *types.Interface, and
+// *types.Union, this is just a single term with Tilde() == false and
+// Type() == typ. For *types.TypeParam, *types.Interface, and *types.Union, see
+// below.
+//
+// Structural type restrictions of a type parameter are created via
+// non-interface types embedded in its constraint interface (directly, or via a
+// chain of interface embeddings). For example, in the declaration type
+// T[P interface{~int; m()}] int the structural restriction of the type
+// parameter P is ~int.
+//
+// With interface embedding and unions, the specification of structural type
+// restrictions may be arbitrarily complex. For example, consider the
+// following:
+//
+// type A interface{ ~string|~[]byte }
+//
+// type B interface{ int|string }
+//
+// type C interface { ~string|~int }
+//
+// type T[P interface{ A|B; C }] int
+//
+// In this example, the structural type restriction of P is ~string|int: A|B
+// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
+// which when intersected with C (~string|~int) yields ~string|int.
+//
+// _NormalTerms computes these expansions and reductions, producing a
+// "normalized" form of the embeddings. A structural restriction is normalized
+// if it is a single union containing no interface terms, and is minimal in the
+// sense that removing any term changes the set of types satisfying the
+// constraint. It is left as a proof for the reader that, modulo sorting, there
+// is exactly one such normalized form.
+//
+// Because the minimal representation always takes this form, _NormalTerms
+// returns a slice of tilde terms corresponding to the terms of the union in
+// the normalized structural restriction. An error is returned if the type is
+// invalid, exceeds complexity bounds, or has an empty type set. In the latter
+// case, _NormalTerms returns ErrEmptyTypeSet.
+//
+// _NormalTerms makes no guarantees about the order of terms, except that it
+// is deterministic.
+func _NormalTerms(typ types.Type) ([]*Term, error) {
+ switch typ := typ.(type) {
+ case *TypeParam:
+ return StructuralTerms(typ)
+ case *Union:
+ return UnionTermSet(typ)
+ case *types.Interface:
+ return InterfaceTermSet(typ)
+ default:
+ return []*Term{NewTerm(false, typ)}, nil
+ }
+}
diff --git a/test/tools/vendor/golang.org/x/tools/internal/typeparams/normalize.go b/test/tools/vendor/golang.org/x/tools/internal/typeparams/normalize.go
index 090f142a5..9c631b651 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/typeparams/normalize.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/typeparams/normalize.go
@@ -24,20 +24,22 @@ var ErrEmptyTypeSet = errors.New("empty type set")
// Structural type restrictions of a type parameter are created via
// non-interface types embedded in its constraint interface (directly, or via a
// chain of interface embeddings). For example, in the declaration
-// type T[P interface{~int; m()}] int
+//
+// type T[P interface{~int; m()}] int
+//
// the structural restriction of the type parameter P is ~int.
//
// With interface embedding and unions, the specification of structural type
// restrictions may be arbitrarily complex. For example, consider the
// following:
//
-// type A interface{ ~string|~[]byte }
+// type A interface{ ~string|~[]byte }
//
-// type B interface{ int|string }
+// type B interface{ int|string }
//
-// type C interface { ~string|~int }
+// type C interface { ~string|~int }
//
-// type T[P interface{ A|B; C }] int
+// type T[P interface{ A|B; C }] int
//
// In this example, the structural type restriction of P is ~string|int: A|B
// expands to ~string|~[]byte|int|string, which reduces to ~string|~[]byte|int,
diff --git a/test/tools/vendor/golang.org/x/tools/internal/typeparams/termlist.go b/test/tools/vendor/golang.org/x/tools/internal/typeparams/termlist.go
index 10857d504..933106a23 100644
--- a/test/tools/vendor/golang.org/x/tools/internal/typeparams/termlist.go
+++ b/test/tools/vendor/golang.org/x/tools/internal/typeparams/termlist.go
@@ -97,15 +97,6 @@ func (xl termlist) norm() termlist {
return rl
}
-// If the type set represented by xl is specified by a single (non-𝓤) term,
-// structuralType returns that type. Otherwise it returns nil.
-func (xl termlist) structuralType() types.Type {
- if nl := xl.norm(); len(nl) == 1 {
- return nl[0].typ // if nl.isAll() then typ is nil, which is ok
- }
- return nil
-}
-
// union returns the union xl ∪ yl.
func (xl termlist) union(yl termlist) termlist {
return append(xl, yl...).norm()
diff --git a/test/tools/vendor/golang.org/x/xerrors/LICENSE b/test/tools/vendor/golang.org/x/xerrors/LICENSE
deleted file mode 100644
index e4a47e17f..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/LICENSE
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2019 The Go Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/test/tools/vendor/golang.org/x/xerrors/PATENTS b/test/tools/vendor/golang.org/x/xerrors/PATENTS
deleted file mode 100644
index 733099041..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/PATENTS
+++ /dev/null
@@ -1,22 +0,0 @@
-Additional IP Rights Grant (Patents)
-
-"This implementation" means the copyrightable works distributed by
-Google as part of the Go project.
-
-Google hereby grants to You a perpetual, worldwide, non-exclusive,
-no-charge, royalty-free, irrevocable (except as stated in this section)
-patent license to make, have made, use, offer to sell, sell, import,
-transfer and otherwise run, modify and propagate the contents of this
-implementation of Go, where such license applies only to those patent
-claims, both currently owned or controlled by Google and acquired in
-the future, licensable by Google that are necessarily infringed by this
-implementation of Go. This grant does not include claims that would be
-infringed only as a consequence of further modification of this
-implementation. If you or your agent or exclusive licensee institute or
-order or agree to the institution of patent litigation against any
-entity (including a cross-claim or counterclaim in a lawsuit) alleging
-that this implementation of Go or any code incorporated within this
-implementation of Go constitutes direct or contributory patent
-infringement, or inducement of patent infringement, then any patent
-rights granted to you under this License for this implementation of Go
-shall terminate as of the date such litigation is filed.
diff --git a/test/tools/vendor/golang.org/x/xerrors/README b/test/tools/vendor/golang.org/x/xerrors/README
deleted file mode 100644
index aac7867a5..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This repository holds the transition packages for the new Go 1.13 error values.
-See golang.org/design/29934-error-values.
diff --git a/test/tools/vendor/golang.org/x/xerrors/adaptor.go b/test/tools/vendor/golang.org/x/xerrors/adaptor.go
deleted file mode 100644
index 4317f2483..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/adaptor.go
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xerrors
-
-import (
- "bytes"
- "fmt"
- "io"
- "reflect"
- "strconv"
-)
-
-// FormatError calls the FormatError method of f with an errors.Printer
-// configured according to s and verb, and writes the result to s.
-func FormatError(f Formatter, s fmt.State, verb rune) {
- // Assuming this function is only called from the Format method, and given
- // that FormatError takes precedence over Format, it cannot be called from
- // any package that supports errors.Formatter. It is therefore safe to
- // disregard that State may be a specific printer implementation and use one
- // of our choice instead.
-
- // limitations: does not support printing error as Go struct.
-
- var (
- sep = " " // separator before next error
- p = &state{State: s}
- direct = true
- )
-
- var err error = f
-
- switch verb {
- // Note that this switch must match the preference order
- // for ordinary string printing (%#v before %+v, and so on).
-
- case 'v':
- if s.Flag('#') {
- if stringer, ok := err.(fmt.GoStringer); ok {
- io.WriteString(&p.buf, stringer.GoString())
- goto exit
- }
- // proceed as if it were %v
- } else if s.Flag('+') {
- p.printDetail = true
- sep = "\n - "
- }
- case 's':
- case 'q', 'x', 'X':
- // Use an intermediate buffer in the rare cases that precision,
- // truncation, or one of the alternative verbs (q, x, and X) are
- // specified.
- direct = false
-
- default:
- p.buf.WriteString("%!")
- p.buf.WriteRune(verb)
- p.buf.WriteByte('(')
- switch {
- case err != nil:
- p.buf.WriteString(reflect.TypeOf(f).String())
- default:
- p.buf.WriteString("<nil>")
- }
- p.buf.WriteByte(')')
- io.Copy(s, &p.buf)
- return
- }
-
-loop:
- for {
- switch v := err.(type) {
- case Formatter:
- err = v.FormatError((*printer)(p))
- case fmt.Formatter:
- v.Format(p, 'v')
- break loop
- default:
- io.WriteString(&p.buf, v.Error())
- break loop
- }
- if err == nil {
- break
- }
- if p.needColon || !p.printDetail {
- p.buf.WriteByte(':')
- p.needColon = false
- }
- p.buf.WriteString(sep)
- p.inDetail = false
- p.needNewline = false
- }
-
-exit:
- width, okW := s.Width()
- prec, okP := s.Precision()
-
- if !direct || (okW && width > 0) || okP {
- // Construct format string from State s.
- format := []byte{'%'}
- if s.Flag('-') {
- format = append(format, '-')
- }
- if s.Flag('+') {
- format = append(format, '+')
- }
- if s.Flag(' ') {
- format = append(format, ' ')
- }
- if okW {
- format = strconv.AppendInt(format, int64(width), 10)
- }
- if okP {
- format = append(format, '.')
- format = strconv.AppendInt(format, int64(prec), 10)
- }
- format = append(format, string(verb)...)
- fmt.Fprintf(s, string(format), p.buf.String())
- } else {
- io.Copy(s, &p.buf)
- }
-}
-
-var detailSep = []byte("\n ")
-
-// state tracks error printing state. It implements fmt.State.
-type state struct {
- fmt.State
- buf bytes.Buffer
-
- printDetail bool
- inDetail bool
- needColon bool
- needNewline bool
-}
-
-func (s *state) Write(b []byte) (n int, err error) {
- if s.printDetail {
- if len(b) == 0 {
- return 0, nil
- }
- if s.inDetail && s.needColon {
- s.needNewline = true
- if b[0] == '\n' {
- b = b[1:]
- }
- }
- k := 0
- for i, c := range b {
- if s.needNewline {
- if s.inDetail && s.needColon {
- s.buf.WriteByte(':')
- s.needColon = false
- }
- s.buf.Write(detailSep)
- s.needNewline = false
- }
- if c == '\n' {
- s.buf.Write(b[k:i])
- k = i + 1
- s.needNewline = true
- }
- }
- s.buf.Write(b[k:])
- if !s.inDetail {
- s.needColon = true
- }
- } else if !s.inDetail {
- s.buf.Write(b)
- }
- return len(b), nil
-}
-
-// printer wraps a state to implement an xerrors.Printer.
-type printer state
-
-func (s *printer) Print(args ...interface{}) {
- if !s.inDetail || s.printDetail {
- fmt.Fprint((*state)(s), args...)
- }
-}
-
-func (s *printer) Printf(format string, args ...interface{}) {
- if !s.inDetail || s.printDetail {
- fmt.Fprintf((*state)(s), format, args...)
- }
-}
-
-func (s *printer) Detail() bool {
- s.inDetail = true
- return s.printDetail
-}
diff --git a/test/tools/vendor/golang.org/x/xerrors/codereview.cfg b/test/tools/vendor/golang.org/x/xerrors/codereview.cfg
deleted file mode 100644
index 3f8b14b64..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/codereview.cfg
+++ /dev/null
@@ -1 +0,0 @@
-issuerepo: golang/go
diff --git a/test/tools/vendor/golang.org/x/xerrors/doc.go b/test/tools/vendor/golang.org/x/xerrors/doc.go
deleted file mode 100644
index eef99d9d5..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/doc.go
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package xerrors implements functions to manipulate errors.
-//
-// This package is based on the Go 2 proposal for error values:
-// https://golang.org/design/29934-error-values
-//
-// These functions were incorporated into the standard library's errors package
-// in Go 1.13:
-// - Is
-// - As
-// - Unwrap
-//
-// Also, Errorf's %w verb was incorporated into fmt.Errorf.
-//
-// Use this package to get equivalent behavior in all supported Go versions.
-//
-// No other features of this package were included in Go 1.13, and at present
-// there are no plans to include any of them.
-package xerrors // import "golang.org/x/xerrors"
diff --git a/test/tools/vendor/golang.org/x/xerrors/errors.go b/test/tools/vendor/golang.org/x/xerrors/errors.go
deleted file mode 100644
index e88d3772d..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/errors.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xerrors
-
-import "fmt"
-
-// errorString is a trivial implementation of error.
-type errorString struct {
- s string
- frame Frame
-}
-
-// New returns an error that formats as the given text.
-//
-// The returned error contains a Frame set to the caller's location and
-// implements Formatter to show this information when printed with details.
-func New(text string) error {
- return &errorString{text, Caller(1)}
-}
-
-func (e *errorString) Error() string {
- return e.s
-}
-
-func (e *errorString) Format(s fmt.State, v rune) { FormatError(e, s, v) }
-
-func (e *errorString) FormatError(p Printer) (next error) {
- p.Print(e.s)
- e.frame.Format(p)
- return nil
-}
diff --git a/test/tools/vendor/golang.org/x/xerrors/fmt.go b/test/tools/vendor/golang.org/x/xerrors/fmt.go
deleted file mode 100644
index 829862ddf..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/fmt.go
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xerrors
-
-import (
- "fmt"
- "strings"
- "unicode"
- "unicode/utf8"
-
- "golang.org/x/xerrors/internal"
-)
-
-const percentBangString = "%!"
-
-// Errorf formats according to a format specifier and returns the string as a
-// value that satisfies error.
-//
-// The returned error includes the file and line number of the caller when
-// formatted with additional detail enabled. If the last argument is an error
-// the returned error's Format method will return it if the format string ends
-// with ": %s", ": %v", or ": %w". If the last argument is an error and the
-// format string ends with ": %w", the returned error implements an Unwrap
-// method returning it.
-//
-// If the format specifier includes a %w verb with an error operand in a
-// position other than at the end, the returned error will still implement an
-// Unwrap method returning the operand, but the error's Format method will not
-// return the wrapped error.
-//
-// It is invalid to include more than one %w verb or to supply it with an
-// operand that does not implement the error interface. The %w verb is otherwise
-// a synonym for %v.
-func Errorf(format string, a ...interface{}) error {
- format = formatPlusW(format)
- // Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
- wrap := strings.HasSuffix(format, ": %w")
- idx, format2, ok := parsePercentW(format)
- percentWElsewhere := !wrap && idx >= 0
- if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
- err := errorAt(a, len(a)-1)
- if err == nil {
- return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
- }
- // TODO: this is not entirely correct. The error value could be
- // printed elsewhere in format if it mixes numbered with unnumbered
- // substitutions. With relatively small changes to doPrintf we can
- // have it optionally ignore extra arguments and pass the argument
- // list in its entirety.
- msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
- frame := Frame{}
- if internal.EnableTrace {
- frame = Caller(1)
- }
- if wrap {
- return &wrapError{msg, err, frame}
- }
- return &noWrapError{msg, err, frame}
- }
- // Support %w anywhere.
- // TODO: don't repeat the wrapped error's message when %w occurs in the middle.
- msg := fmt.Sprintf(format2, a...)
- if idx < 0 {
- return &noWrapError{msg, nil, Caller(1)}
- }
- err := errorAt(a, idx)
- if !ok || err == nil {
- // Too many %ws or argument of %w is not an error. Approximate the Go
- // 1.13 fmt.Errorf message.
- return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
- }
- frame := Frame{}
- if internal.EnableTrace {
- frame = Caller(1)
- }
- return &wrapError{msg, err, frame}
-}
-
-func errorAt(args []interface{}, i int) error {
- if i < 0 || i >= len(args) {
- return nil
- }
- err, ok := args[i].(error)
- if !ok {
- return nil
- }
- return err
-}
-
-// formatPlusW is used to avoid the vet check that will barf at %w.
-func formatPlusW(s string) string {
- return s
-}
-
-// Return the index of the only %w in format, or -1 if none.
-// Also return a rewritten format string with %w replaced by %v, and
-// false if there is more than one %w.
-// TODO: handle "%[N]w".
-func parsePercentW(format string) (idx int, newFormat string, ok bool) {
- // Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
- idx = -1
- ok = true
- n := 0
- sz := 0
- var isW bool
- for i := 0; i < len(format); i += sz {
- if format[i] != '%' {
- sz = 1
- continue
- }
- // "%%" is not a format directive.
- if i+1 < len(format) && format[i+1] == '%' {
- sz = 2
- continue
- }
- sz, isW = parsePrintfVerb(format[i:])
- if isW {
- if idx >= 0 {
- ok = false
- } else {
- idx = n
- }
- // "Replace" the last character, the 'w', with a 'v'.
- p := i + sz - 1
- format = format[:p] + "v" + format[p+1:]
- }
- n++
- }
- return idx, format, ok
-}
-
-// Parse the printf verb starting with a % at s[0].
-// Return how many bytes it occupies and whether the verb is 'w'.
-func parsePrintfVerb(s string) (int, bool) {
- // Assume only that the directive is a sequence of non-letters followed by a single letter.
- sz := 0
- var r rune
- for i := 1; i < len(s); i += sz {
- r, sz = utf8.DecodeRuneInString(s[i:])
- if unicode.IsLetter(r) {
- return i + sz, r == 'w'
- }
- }
- return len(s), false
-}
-
-type noWrapError struct {
- msg string
- err error
- frame Frame
-}
-
-func (e *noWrapError) Error() string {
- return fmt.Sprint(e)
-}
-
-func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
-
-func (e *noWrapError) FormatError(p Printer) (next error) {
- p.Print(e.msg)
- e.frame.Format(p)
- return e.err
-}
-
-type wrapError struct {
- msg string
- err error
- frame Frame
-}
-
-func (e *wrapError) Error() string {
- return fmt.Sprint(e)
-}
-
-func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
-
-func (e *wrapError) FormatError(p Printer) (next error) {
- p.Print(e.msg)
- e.frame.Format(p)
- return e.err
-}
-
-func (e *wrapError) Unwrap() error {
- return e.err
-}
diff --git a/test/tools/vendor/golang.org/x/xerrors/format.go b/test/tools/vendor/golang.org/x/xerrors/format.go
deleted file mode 100644
index 1bc9c26b9..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/format.go
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xerrors
-
-// A Formatter formats error messages.
-type Formatter interface {
- error
-
- // FormatError prints the receiver's first error and returns the next error in
- // the error chain, if any.
- FormatError(p Printer) (next error)
-}
-
-// A Printer formats error messages.
-//
-// The most common implementation of Printer is the one provided by package fmt
-// during Printf (as of Go 1.13). Localization packages such as golang.org/x/text/message
-// typically provide their own implementations.
-type Printer interface {
- // Print appends args to the message output.
- Print(args ...interface{})
-
- // Printf writes a formatted string.
- Printf(format string, args ...interface{})
-
- // Detail reports whether error detail is requested.
- // After the first call to Detail, all text written to the Printer
- // is formatted as additional detail, or ignored when
- // detail has not been requested.
- // If Detail returns false, the caller can avoid printing the detail at all.
- Detail() bool
-}
diff --git a/test/tools/vendor/golang.org/x/xerrors/frame.go b/test/tools/vendor/golang.org/x/xerrors/frame.go
deleted file mode 100644
index 0de628ec5..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/frame.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xerrors
-
-import (
- "runtime"
-)
-
-// A Frame contains part of a call stack.
-type Frame struct {
- // Make room for three PCs: the one we were asked for, what it called,
- // and possibly a PC for skipPleaseUseCallersFrames. See:
- // https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
- frames [3]uintptr
-}
-
-// Caller returns a Frame that describes a frame on the caller's stack.
-// The argument skip is the number of frames to skip over.
-// Caller(0) returns the frame for the caller of Caller.
-func Caller(skip int) Frame {
- var s Frame
- runtime.Callers(skip+1, s.frames[:])
- return s
-}
-
-// location reports the file, line, and function of a frame.
-//
-// The returned function may be "" even if file and line are not.
-func (f Frame) location() (function, file string, line int) {
- frames := runtime.CallersFrames(f.frames[:])
- if _, ok := frames.Next(); !ok {
- return "", "", 0
- }
- fr, ok := frames.Next()
- if !ok {
- return "", "", 0
- }
- return fr.Function, fr.File, fr.Line
-}
-
-// Format prints the stack as error detail.
-// It should be called from an error's Format implementation
-// after printing any other error detail.
-func (f Frame) Format(p Printer) {
- if p.Detail() {
- function, file, line := f.location()
- if function != "" {
- p.Printf("%s\n ", function)
- }
- if file != "" {
- p.Printf("%s:%d\n", file, line)
- }
- }
-}
diff --git a/test/tools/vendor/golang.org/x/xerrors/go.mod b/test/tools/vendor/golang.org/x/xerrors/go.mod
deleted file mode 100644
index 870d4f612..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/go.mod
+++ /dev/null
@@ -1,3 +0,0 @@
-module golang.org/x/xerrors
-
-go 1.11
diff --git a/test/tools/vendor/golang.org/x/xerrors/internal/internal.go b/test/tools/vendor/golang.org/x/xerrors/internal/internal.go
deleted file mode 100644
index 89f4eca5d..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/internal/internal.go
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package internal
-
-// EnableTrace indicates whether stack information should be recorded in errors.
-var EnableTrace = true
diff --git a/test/tools/vendor/golang.org/x/xerrors/wrap.go b/test/tools/vendor/golang.org/x/xerrors/wrap.go
deleted file mode 100644
index 9a3b51037..000000000
--- a/test/tools/vendor/golang.org/x/xerrors/wrap.go
+++ /dev/null
@@ -1,106 +0,0 @@
-// Copyright 2018 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package xerrors
-
-import (
- "reflect"
-)
-
-// A Wrapper provides context around another error.
-type Wrapper interface {
- // Unwrap returns the next error in the error chain.
- // If there is no next error, Unwrap returns nil.
- Unwrap() error
-}
-
-// Opaque returns an error with the same error formatting as err
-// but that does not match err and cannot be unwrapped.
-func Opaque(err error) error {
- return noWrapper{err}
-}
-
-type noWrapper struct {
- error
-}
-
-func (e noWrapper) FormatError(p Printer) (next error) {
- if f, ok := e.error.(Formatter); ok {
- return f.FormatError(p)
- }
- p.Print(e.error)
- return nil
-}
-
-// Unwrap returns the result of calling the Unwrap method on err, if err implements
-// Unwrap. Otherwise, Unwrap returns nil.
-func Unwrap(err error) error {
- u, ok := err.(Wrapper)
- if !ok {
- return nil
- }
- return u.Unwrap()
-}
-
-// Is reports whether any error in err's chain matches target.
-//
-// An error is considered to match a target if it is equal to that target or if
-// it implements a method Is(error) bool such that Is(target) returns true.
-func Is(err, target error) bool {
- if target == nil {
- return err == target
- }
-
- isComparable := reflect.TypeOf(target).Comparable()
- for {
- if isComparable && err == target {
- return true
- }
- if x, ok := err.(interface{ Is(error) bool }); ok && x.Is(target) {
- return true
- }
- // TODO: consider supporing target.Is(err). This would allow
- // user-definable predicates, but also may allow for coping with sloppy
- // APIs, thereby making it easier to get away with them.
- if err = Unwrap(err); err == nil {
- return false
- }
- }
-}
-
-// As finds the first error in err's chain that matches the type to which target
-// points, and if so, sets the target to its value and returns true. An error
-// matches a type if it is assignable to the target type, or if it has a method
-// As(interface{}) bool such that As(target) returns true. As will panic if target
-// is not a non-nil pointer to a type which implements error or is of interface type.
-//
-// The As method should set the target to its value and return true if err
-// matches the type to which target points.
-func As(err error, target interface{}) bool {
- if target == nil {
- panic("errors: target cannot be nil")
- }
- val := reflect.ValueOf(target)
- typ := val.Type()
- if typ.Kind() != reflect.Ptr || val.IsNil() {
- panic("errors: target must be a non-nil pointer")
- }
- if e := typ.Elem(); e.Kind() != reflect.Interface && !e.Implements(errorType) {
- panic("errors: *target must be interface or implement error")
- }
- targetType := typ.Elem()
- for err != nil {
- if reflect.TypeOf(err).AssignableTo(targetType) {
- val.Elem().Set(reflect.ValueOf(err))
- return true
- }
- if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) {
- return true
- }
- err = Unwrap(err)
- }
- return false
-}
-
-var errorType = reflect.TypeOf((*error)(nil)).Elem()
diff --git a/test/tools/vendor/modules.txt b/test/tools/vendor/modules.txt
index 462abe617..5b5cc4112 100644
--- a/test/tools/vendor/modules.txt
+++ b/test/tools/vendor/modules.txt
@@ -19,7 +19,7 @@ github.com/vbatts/git-validation/rules/dco
github.com/vbatts/git-validation/rules/messageregexp
github.com/vbatts/git-validation/rules/shortsubject
github.com/vbatts/git-validation/validate
-# golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
+# golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/module
golang.org/x/mod/semver
@@ -27,7 +27,7 @@ golang.org/x/mod/semver
golang.org/x/sys/execabs
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/unix
-# golang.org/x/tools v0.1.10
+# golang.org/x/tools v0.1.11
## explicit
golang.org/x/tools/cmd/goimports
golang.org/x/tools/go/ast/astutil
@@ -40,6 +40,3 @@ golang.org/x/tools/internal/gocommand
golang.org/x/tools/internal/gopathwalk
golang.org/x/tools/internal/imports
golang.org/x/tools/internal/typeparams
-# golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
-golang.org/x/xerrors
-golang.org/x/xerrors/internal