summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/apiv2/10-images.at2
-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/60-auth.at4
-rw-r--r--test/apiv2/70-short-names.at2
-rwxr-xr-xtest/apiv2/test-apiv2113
-rwxr-xr-xtest/buildah-bud/apply-podman-deltas47
-rw-r--r--test/buildah-bud/buildah-tests.diff25
-rwxr-xr-xtest/buildah-bud/run-buildah-bud-tests6
-rw-r--r--test/e2e/build_test.go4
-rw-r--r--test/e2e/checkpoint_test.go128
-rw-r--r--test/e2e/common_test.go4
-rw-r--r--test/e2e/config.go2
-rw-r--r--test/e2e/create_staticip_test.go2
-rw-r--r--test/e2e/create_staticmac_test.go2
-rw-r--r--test/e2e/events_test.go21
-rw-r--r--test/e2e/image_scp_test.go32
-rw-r--r--test/e2e/logs_test.go21
-rw-r--r--test/e2e/manifest_test.go21
-rw-r--r--test/e2e/network_connect_disconnect_test.go9
-rw-r--r--test/e2e/network_test.go20
-rw-r--r--test/e2e/pause_test.go2
-rw-r--r--test/e2e/play_kube_test.go8
-rw-r--r--test/e2e/pod_clone_test.go158
-rw-r--r--test/e2e/pod_create_test.go45
-rw-r--r--test/e2e/pod_infra_container_test.go16
-rw-r--r--test/e2e/prune_test.go23
-rw-r--r--test/e2e/push_test.go2
-rw-r--r--test/e2e/run_privileged_test.go24
-rw-r--r--test/e2e/run_staticip_test.go2
-rw-r--r--test/e2e/run_volume_test.go95
-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.go11
-rw-r--r--test/e2e/systemd_activate_test.go57
-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.bats2
-rw-r--r--test/system/030-run.bats31
-rw-r--r--test/system/065-cp.bats100
-rw-r--r--test/system/070-build.bats9
-rw-r--r--test/system/120-load.bats24
-rw-r--r--test/system/150-login.bats2
-rw-r--r--test/system/160-volumes.bats23
-rw-r--r--test/system/170-run-userns.bats35
-rw-r--r--test/system/200-pod.bats41
-rw-r--r--test/system/250-systemd.bats58
-rw-r--r--test/system/410-selinux.bats6
-rw-r--r--test/system/500-networking.bats21
-rw-r--r--test/system/520-checkpoint.bats30
-rw-r--r--test/system/600-completion.bats18
-rwxr-xr-xtest/system/build-testimage76
-rw-r--r--test/system/helpers.bash35
-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.go23
-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
107 files changed, 1896 insertions, 1109 deletions
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 13aaea317..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
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/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 dbf816f55..bd7f8e7bd 100644
--- a/test/apiv2/70-short-names.at
+++ b/test/apiv2/70-short-names.at
@@ -128,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/test-apiv2 b/test/apiv2/test-apiv2
index c3545522e..8548d84e5 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)
@@ -62,7 +64,7 @@ clean_up_server() {
podman rm -a
podman rmi -af
- stop_registry
+ stop_registry --cleanup
stop_service
fi
}
@@ -87,6 +89,7 @@ trap err_handler ERR
#########
function die() {
echo "$ME: $*" >&2
+ clean_up_server
exit 1
}
@@ -219,19 +222,19 @@ function jsonify() {
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.
+ # 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 +244,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 +272,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,7 +284,7 @@ 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}' \
@@ -289,8 +292,7 @@ function t() {
# 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
+ die "curl failure ($rc) on $url - cannot continue"
fi
# Show returned headers (without trailing ^M or empty lines) in log file.
@@ -380,11 +382,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 +400,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 +410,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 +427,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 +451,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 e2ca45728..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,21 +193,12 @@ skip_if_remote "volumes don't work with podman-remote" \
"buildah bud --volume" \
"buildah-bud-policy"
-# Most of this should work in podman remote after API implementation other than where context is host.
skip_if_remote "--build-context option not implemented in podman-remote" \
- "build-with-additional-build-context and COPY, test pinning image" \
- "build-with-additional-build-context and COPY, stagename and additional-context conflict" \
- "build-with-additional-build-context and COPY, additionalContext and numeric value of stage" \
- "build-with-additional-build-context and COPY, additionalContext and numeric value of stage" \
"build-with-additional-build-context and COPY, additional context from host" \
- "build-with-additional-build-context and COPY, additional context from external URL" \
- "build-with-additional-build-context and RUN --mount=from=, additional-context is URL and mounted from subdir" \
"build-with-additional-build-context and RUN --mount=from=, additional-context not image and also test conflict with stagename" \
- "build-with-additional-build-context and RUN --mount=from=, additional-context and also test conflict with stagename" \
- "bud-multiple-platform for --all-platform with additional-build-context" \
- "build-with-additional-build-context and FROM, stagename and additional-context conflict" \
+
+skip_if_remote "env-variable for Containerfile.in pre-processing is not propogated on remote" \
"bud with Containerfile.in, via envariable" \
- "build-with-additional-build-context and FROM, pin busybox to alpine"
# Requires a local file outside context dir
skip_if_remote "local keyfile not sent to podman-remote" \
@@ -226,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.
@@ -238,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/e2e/build_test.go b/test/e2e/build_test.go
index 86dc76116..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"))
@@ -555,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 1da199714..be976207e 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
@@ -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))
@@ -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))
@@ -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))
@@ -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/common_test.go b/test/e2e/common_test.go
index db194b777..261db8a9a 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -41,7 +41,7 @@ var (
CGROUP_MANAGER = "systemd" //nolint:revive,stylecheck
RESTORE_IMAGES = []string{ALPINE, BB, nginx} //nolint:revive,stylecheck
defaultWaitTimeout = 90
- CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode() //nolint:revive,stylecheck
+ CGROUPSV2, _ = cgroups.IsCgroup2UnifiedMode()
)
// PodmanTestIntegration struct for command line options
@@ -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
diff --git a/test/e2e/config.go b/test/e2e/config.go
index 2ca8e2a15..fbcc9dfff 100644
--- a/test/e2e/config.go
+++ b/test/e2e/config.go
@@ -15,7 +15,7 @@ var (
healthcheck = "quay.io/libpod/alpine_healthcheck:latest"
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/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/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/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/logs_test.go b/test/e2e/logs_test.go
index 0d24a7e17..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"
@@ -370,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..2fffc9118 100644
--- a/test/e2e/manifest_test.go
+++ b/test/e2e/manifest_test.go
@@ -91,6 +91,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()
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index 019bb4617..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,7 @@ 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"})
@@ -211,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"
@@ -240,7 +239,7 @@ 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"})
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index 715455521..2fdd62f7e 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
diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go
index 402719de2..566aca07e 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() {
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 31044f68b..61f2b3a1c 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -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
@@ -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
@@ -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
@@ -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
diff --git a/test/e2e/pod_clone_test.go b/test/e2e/pod_clone_test.go
new file mode 100644
index 000000000..b90bf10da
--- /dev/null
+++ b/test/e2e/pod_clone_test.go
@@ -0,0 +1,158 @@
+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
+ )
+
+ 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"))
+ })
+
+})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index dedb1caeb..a48193e90 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -1112,4 +1112,49 @@ 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))
+ })
+
})
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index ad2db2411..20794a29c 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -130,14 +130,24 @@ var _ = Describe("Podman pod create", func() {
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"run", "-dt", "--pod", session.OutputToString(), ALPINE})
+ session = podmanTest.Podman([]string{"run", "--name", "hostCtr", "--pod", session.OutputToString(), ALPINE, "readlink", "/proc/self/ns/net"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
- session = podmanTest.Podman([]string{"inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", session.OutputToString()})
+ 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(ContainSubstring("''")) // no network path... host
+ Expect(session.OutputToString()).Should(Equal("''")) // no network path... host
+
})
It("podman pod correctly sets up IPCNS", func() {
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/push_test.go b/test/e2e/push_test.go
index 0288bf915..864278777 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -96,7 +96,6 @@ 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")
}
@@ -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()
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..09fb4e03c 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")
})
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index 3bef889b7..8cc2a68de 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -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() {
@@ -863,6 +916,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 +961,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/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..712d16a6a 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() {
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/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 1356c99a0..dd5a7ed44 100644
--- a/test/system/015-help.bats
+++ b/test/system/015-help.bats
@@ -199,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 241831257..56cf4f266 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
diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats
index cfbeff3ae..12c6e1a01 100644
--- a/test/system/065-cp.bats
+++ b/test/system/065-cp.bats
@@ -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 5a7f63b43..7f0bcfd95 100644
--- a/test/system/120-load.bats
+++ b/test/system/120-load.bats
@@ -128,8 +128,24 @@ verify_iid_and_name() {
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/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 797883ec6..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)
diff --git a/test/system/170-run-userns.bats b/test/system/170-run-userns.bats
index 46cb37b9d..84788a7f4 100644
--- a/test/system/170-run-userns.bats
+++ b/test/system/170-run-userns.bats
@@ -111,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 404ad67ec..92d3966be 100644
--- a/test/system/200-pod.bats
+++ b/test/system/200-pod.bats
@@ -472,4 +472,45 @@ 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
+ 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"
+ run_podman pod --cgroup-manager=systemd rm -f $name1
+
+ local name2="resources2"
+ run_podman --cgroup-manager=cgroupfs pod create --cpus=5 --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"
+ 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 110d425d2..e251e8a6d 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"
@@ -88,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.
@@ -235,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" {
@@ -295,6 +304,8 @@ LISTEN_FDNAMES=listen_fdnames" | sort)
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
@@ -360,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..0d724985e 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,12 +676,12 @@ 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)
+ local port="${test%-*}"
+ local end_port="${test#-*}"
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
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 2de9b1ae1..cb4a2c5f8 100644
--- a/test/system/600-completion.bats
+++ b/test/system/600-completion.bats
@@ -341,7 +341,9 @@ function _check_no_suggestions() {
skip_if_remote "mounting via remote does not work"
for cmd in create run; do
run_completion $cmd $IMAGE ""
- assert "$output" =~ ".*^/etc\$.*^/home\$.*^/root\$.*" "root directories suggested (cmd: podman $cmd)"
+ 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"
@@ -354,23 +356,31 @@ function _check_no_suggestions() {
# 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\$.*^../../home\$.*" "relative root directories suggested (cmd: podman $cmd ../../)"
+ 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 touch /tmp/$random_file
+ 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"
+ 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 fe9e971fb..273e8d2f5 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,35 @@ 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 all_ports_free=1
+ for i in $(seq 2 $size); do
+ if ! port_is_free $((firstport + $i)); then
+ all_ports_free=
+ break
+ fi
+ done
+ if [[ -n "$all_ports_free" ]]; then
+ echo "$firstport-$((firstport + $size - 1))"
+ 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
###################
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..99c6fb694 100644
--- a/test/testvol/main.go
+++ b/test/testvol/main.go
@@ -14,13 +14,20 @@ import (
)
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
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..7a0aeba86
--- /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)
+}
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