diff options
Diffstat (limited to 'test')
87 files changed, 1297 insertions, 1044 deletions
diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at index a994f8e11..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 @@ -156,6 +156,17 @@ t GET images/json?filters='{"reference":["test1"]}' 200 length=1 t DELETE libpod/images/test1:latest 200 +# to be used in prune until filter tests +podman image build -t docker.io/library/test1:latest -<<EOF +from alpine +RUN >file4 +EOF +podman create --name test1 test1 echo hi + +t DELETE images/test1:latest 409 +podman rm test1 +t DELETE images/test1:latest 200 + t GET "images/get?names=alpine" 200 '[POSIX tar archive]' podman pull busybox @@ -214,6 +225,18 @@ t POST "images/load" ${TMPD}/test.tar 200 \ t GET libpod/images/quay.io/libpod/alpine:latest/exists 204 t GET libpod/images/quay.io/libpod/busybox:latest/exists 204 +CONTAINERFILE_WITH_ERR_TAR="${TMPD}/containerfile.tar" +cat > $TMPD/containerfile << EOF +FROM quay.io/fedora/fedora +RUN echo 'some error' >&2 +EOF +tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_WITH_ERR_TAR} containerfile &> /dev/null +t POST "build?q=1&dockerfile=containerfile" $CONTAINERFILE_WITH_ERR_TAR 200 +response_output=$(cat "$WORKDIR/curl.result.out") +if [[ ${response_output} == *"some error"* ]];then + _show_ok 0 "compat quiet build" "~ $response_output" "found output from stderr in API" +fi + cleanBuildTest # vim: filetype=sh diff --git a/test/apiv2/12-imagesMore.at b/test/apiv2/12-imagesMore.at index 67b4f1c79..57d5e114d 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,38 @@ 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 \ - .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 7a38dfea0..383c527b4 100644 --- a/test/apiv2/20-containers.at +++ b/test/apiv2/20-containers.at @@ -45,16 +45,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 \ @@ -239,6 +239,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='[]' \ diff --git a/test/apiv2/60-auth.at b/test/apiv2/60-auth.at index 1e087d12b..465b0a96d 100644 --- a/test/apiv2/60-auth.at +++ b/test/apiv2/60-auth.at @@ -3,7 +3,7 @@ # registry-related tests # -start_registry +start_registry htpasswd # Test unreachable t POST /v1.40/auth username=$REGISTRY_USERNAME password=WrOnGPassWord serveraddress=does.not.exist.io:1234/ \ @@ -26,3 +26,5 @@ t POST /v1.40/auth username=$REGISTRY_USERNAME password=$REGISTRY_PASSWORD serve 200 \ .Status="Login Succeeded" \ .IdentityToken="" + +stop_registry diff --git a/test/apiv2/70-short-names.at b/test/apiv2/70-short-names.at index a5087c115..bd7f8e7bd 100644 --- a/test/apiv2/70-short-names.at +++ b/test/apiv2/70-short-names.at @@ -6,11 +6,16 @@ # Pull the libpod/quay image which is used in all tests below. t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .status~".*Download complete.*" +# 14291 - let a short-name resolve to a *local* non Docker-Hub image. +t POST containers/create Image=alpine 201 .Id~[0-9a-f]\\{64\\} +cid=$(jq -r '.Id' <<<"$output") +t GET containers/$cid/json 200 .Image="quay.io/libpod/alpine:latest" +podman rm -f $cid ########## TAG t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201 -t DELETE "images/foo" 200 +t DELETE "images/docker.io/library/foo" 200 ########## BUILD @@ -52,9 +57,6 @@ t DELETE "images/foo" 200 ########## TAG -# Looking up 'alpine' will fail as it gets normalized to docker.io. -t POST "images/alpine/tag?repo=foo" 404 .cause="image not known" - # The libpod endpoint will resolve to it without issues. t GET "libpod/images/alpine/exists" 204 @@ -67,22 +69,21 @@ t GET "libpod/images/docker.io/library/foo/exists" 204 ########## REMOVE -t DELETE "images/alpine" 404 .cause="image not known" # fails since docker.io/library/alpine does not exist t DELETE "images/foo" 200 # removes the previously tagged image ########## GET # Same procedure as above but with the /get endpoint. -t GET "images/alpine/get" 404 .cause="image not known" t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201 t GET "images/foo/get" 200 '[POSIX tar archive]' t DELETE "images/foo" 200 +t GET "images/alpine/get" 200 ########## HISTORY -t GET "images/alpine/history" 404 .cause="image not known" +t GET "images/alpine/history" 200 t GET "images/quay.io/libpod/alpine/history" 200 t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201 t GET "libpod/images/foo/history" 200 @@ -91,7 +92,7 @@ t DELETE "images/foo" 200 ########## PUSH -t POST "images/alpine/push?destination=localhost:9999/do/not:exist" 404 .cause="image not known" +t POST "images/alpine/push?destination=localhost:9999/do:exist" 200 t POST "images/quay.io/libpod/alpine/push?destination=localhost:9999/do/not:exist" 200 # Error is in the response t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201 t POST "images/foo/push?destination=localhost:9999/do/not:exist" 200 # Error is in the response @@ -100,7 +101,7 @@ t DELETE "images/foo" ########## CREATE A CONTAINER -t POST "containers/create" Image=alpine 404 .cause="image not known" +t POST "containers/create" Image=alpine 201 t POST "containers/create" Image=quay.io/libpod/alpine:latest 201 cid=$(jq -r '.Id' <<<"$output") t POST "images/quay.io/libpod/alpine/tag?repo=foo" 201 @@ -113,7 +114,7 @@ t DELETE "containers/$cid" t POST "containers/create" Image=quay.io/libpod/alpine:latest 201 cid=$(jq -r '.Id' <<<"$output") -t GET "images/alpine/get" 404 .cause="image not known" +t GET "images/alpine/get" 200 t POST "commit?container=$cid&repo=foo&tag=tag" 201 t GET "images/foo/get" 404 .cause="image not known" t GET "images/foo:tag/get" 200 @@ -127,7 +128,7 @@ t DELETE "containers/$cid" # disable the docker.io enforcement. stop_service -CONTAINERS_CONF=$(pwd)/test/apiv2/containers.conf start_service +CONTAINERS_CONF=$TESTS_DIR/containers.conf start_service t POST "images/create?fromImage=quay.io/libpod/alpine:latest" 200 .error~null .status~".*Download complete.*" t POST "images/alpine/tag?repo=foo" 201 diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2 index c3545522e..25f648d93 100755 --- a/test/apiv2/test-apiv2 +++ b/test/apiv2/test-apiv2 @@ -62,7 +62,7 @@ clean_up_server() { podman rm -a podman rmi -af - stop_registry + stop_registry --cleanup stop_service fi } @@ -87,6 +87,7 @@ trap err_handler ERR ######### function die() { echo "$ME: $*" >&2 + clean_up_server exit 1 } @@ -219,19 +220,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 +242,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 +270,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 +282,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 +290,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 +380,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 +398,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 +408,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 +425,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 +449,65 @@ function start_registry() { podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE || podman ${PODMAN_REGISTRY_ARGS} pull $REGISTRY_IMAGE - # Create a local cert and credentials - # FIXME: is there a hidden "--quiet" flag? This is too noisy. - openssl req -newkey rsa:4096 -nodes -sha256 \ - -keyout $AUTHDIR/domain.key -x509 -days 2 \ - -out $AUTHDIR/domain.crt \ - -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=registry host certificate" \ - -addext subjectAltName=DNS:localhost - htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \ - > $AUTHDIR/htpasswd + # Create a local cert (no need to do this more than once) + if [[ ! -e $AUTHDIR/domain.key ]]; then + # FIXME: is there a hidden "--quiet" flag? This is too noisy. + openssl req -newkey rsa:4096 -nodes -sha256 \ + -keyout $AUTHDIR/domain.key -x509 -days 2 \ + -out $AUTHDIR/domain.crt \ + -subj "/C=US/ST=Foo/L=Bar/O=Red Hat, Inc./CN=registry host certificate" \ + -addext subjectAltName=DNS:localhost + fi + + # If invoked with auth=htpasswd, create credentials + REGISTRY_USERNAME= + REGISTRY_PASSWORD= + declare -a registry_auth_params=(-e "REGISTRY_AUTH=$auth") + if [[ "$auth" = "htpasswd" ]]; then + REGISTRY_USERNAME=u$(random_string 7) + REGISTRY_PASSWORD=p$(random_string 7) + + htpasswd -Bbn ${REGISTRY_USERNAME} ${REGISTRY_PASSWORD} \ + > $AUTHDIR/htpasswd + + registry_auth_params+=( + -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" + -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" + ) + fi # Run the registry, and wait for it to come up podman ${PODMAN_REGISTRY_ARGS} run -d \ -p ${REGISTRY_PORT}:5000 \ --name registry \ -v $AUTHDIR:/auth:Z \ - -e "REGISTRY_AUTH=htpasswd" \ - -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \ - -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \ + "${registry_auth_params[@]}" \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/auth/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/auth/domain.key \ ${REGISTRY_IMAGE} wait_for_port localhost $REGISTRY_PORT 10 + echo "# started registry (auth=$auth) on port $PORT" } function stop_registry() { local REGDIR=${WORKDIR}/registry if [[ -d $REGDIR ]]; then local OPTS="--root ${REGDIR}/root --runroot ${REGDIR}/runroot" - podman $OPTS stop -f -t 0 -a + podman $OPTS stop -i -t 0 registry # rm/rmi are important when running rootless: without them we # get EPERMS in tmpdir cleanup because files are owned by subuids. - podman $OPTS rm -f -a - podman $OPTS rmi -f -a + podman $OPTS rm -f -i registry + if [[ "$1" = "--cleanup" ]]; then + podman $OPTS rmi -f -a + fi + echo "# stopped registry on port $PORT" fi + + REGISTRY_PORT= + REGISTRY_USERNAME= + REGISTRY_PASSWORD= } ################# diff --git a/test/buildah-bud/apply-podman-deltas b/test/buildah-bud/apply-podman-deltas index 1ca171c4a..0b691dd0e 100755 --- a/test/buildah-bud/apply-podman-deltas +++ b/test/buildah-bud/apply-podman-deltas @@ -61,7 +61,12 @@ function _skip() { local skip=$1; shift local reason=$1; shift - # All further arguments are test names + # All further arguments are test names. Make sure we're invoked with some! + if [[ -z "$*" ]]; then + echo "$ME: FATAL: Invalid use of '${FUNCNAME[1]}' at line ${BASH_LINENO[1]}: missing test-name argument(s)." >&2 + exit 1 + fi + for t in "$@"; do if fgrep -qx "@test \"$t\" {" $BUD; then $ECHO "@test \"$t\" : $skip \"$reason\"" @@ -150,13 +155,7 @@ errmsg "checking authfile: stat /tmp/nonexistent: no such file or directory" \ ############################################################################### # BEGIN tests that don't make sense under podman due to fundamental differences -# TODO -# Normally, when buildah exits 1 on error, podman exits 125. -# These tests are the exception. They exit 1 under podman. -skip "these tests exit 1 under podman, not 125" \ - "bud with --add-host" \ - "bud - invalid runtime flags test" - +# Fails with "Error: no context directory and no Containerfile specified" skip "does not work under podman" \ "bud without any arguments should succeed" @@ -167,8 +166,9 @@ skip "does not work under podman" \ skip "FIXME FIXME FIXME: argument-order incompatible with podman" \ "bud-squash-hardlinks" -skip "FIXME FIXME FIXME: this passes on Ed's laptop, fails in CI??" \ - "bud-multi-stage-nocache-nocommit" +# Fails with "Error: context must be a directory: /path/to/Dockerfile" +skip "podman-build fails with 'context must be a directory'" \ + "bud with specified context should succeed if context contains existing Dockerfile" ############################################################################### # BEGIN tests which are skipped because they make no sense under podman-remote @@ -193,6 +193,13 @@ skip_if_remote "volumes don't work with podman-remote" \ "buildah bud --volume" \ "buildah-bud-policy" +skip_if_remote "--build-context option not implemented in podman-remote" \ + "build-with-additional-build-context and COPY, additional context from host" \ + "build-with-additional-build-context and RUN --mount=from=, additional-context not image and also test conflict with stagename" \ + +skip_if_remote "env-variable for Containerfile.in pre-processing is not propogated on remote" \ + "bud with Containerfile.in, via envariable" \ + # Requires a local file outside context dir skip_if_remote "local keyfile not sent to podman-remote" \ "bud with encrypted FROM image" @@ -210,6 +217,12 @@ skip_if_remote "--output option not implemented in podman-remote" \ "build with custom build output and output rootfs to tar by pipe" \ "build with custom build output must fail for bad input" +# https://github.com/containers/podman/issues/14544 +skip_if_remote "logfile not implemented on remote" "bud-logfile-with-split-logfile-by-platform" + +skip_if_remote "envariables do not automatically work with -remote." \ + "build proxy" + ############################################################################### # BEGIN tests which are skipped due to actual podman or podman-remote bugs. @@ -222,10 +235,12 @@ skip_if_remote "FIXME FIXME FIXME: find a way to clean up their podman calls" \ "bud with run should not leave mounts behind cleanup test" \ "bud with custom files in /run/ should persist cleanup test" -skip_if_remote "Do envariables work with -remote? Please look into this." \ - "build proxy" +# Under podman-remote, the "Ignoring <stdin>:5:2: error: #error" message +# is never seen. (Not even as stdout/stderr on the server; Ed checked). +skip_if_remote "FIXME FIXME FIXME: 'Ignoring' warning is never seen" \ + "bud with preprocessor error" +# END tests which are skipped due to actual podman or podman-remote bugs. ############################################################################### -# Done. exit $RC diff --git a/test/buildah-bud/buildah-tests.diff b/test/buildah-bud/buildah-tests.diff index 6fa36d904..399042240 100644 --- a/test/buildah-bud/buildah-tests.diff +++ b/test/buildah-bud/buildah-tests.diff @@ -1,15 +1,15 @@ -From 8a8fa1a75e0fa3261263afbc8c2504feb430df6a Mon Sep 17 00:00:00 2001 +From 6508e3df2a129554fdf8336d8a6f0cdcc6fd4832 Mon Sep 17 00:00:00 2001 From: Ed Santiago <santiago@redhat.com> Date: Tue, 9 Feb 2021 17:28:05 -0700 Subject: [PATCH] tweaks for running buildah tests under podman Signed-off-by: Ed Santiago <santiago@redhat.com> --- - tests/helpers.bash | 69 ++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 66 insertions(+), 3 deletions(-) + tests/helpers.bash | 70 ++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/tests/helpers.bash b/tests/helpers.bash -index e3087063..b3a8f5ee 100644 +index e3087063..178a486e 100644 --- a/tests/helpers.bash +++ b/tests/helpers.bash @@ -51,6 +51,23 @@ EOF @@ -60,13 +60,13 @@ index e3087063..b3a8f5ee 100644 # There are various scenarios where we would like to execute `tests` as rootless user, however certain commands like `buildah mount` # do not work in rootless session since a normal user cannot mount a filesystem unless they're in a user namespace along with its # own mount namespace. In order to run such specific commands from a rootless session we must perform `buildah unshare`. -@@ -247,8 +274,35 @@ function run_buildah() { +@@ -247,8 +274,36 @@ function run_buildah() { --retry) retry=3; shift;; # retry network flakes esac + local podman_or_buildah=${BUILDAH_BINARY} + local _opts="${ROOTDIR_OPTS} ${BUILDAH_REGISTRY_OPTS}" -+ if [[ $1 == "build" || $1 == "build-using-dockerfile" ]]; then ++ if [[ $1 == "build" || $1 == "build-using-dockerfile" || $1 == "bud" ]]; then + shift + # podman defaults to --layers=true; buildah to --false. + # If command line includes explicit --layers, leave it untouched, @@ -82,10 +82,11 @@ index e3087063..b3a8f5ee 100644 + _opts= + fi + -+ # podman always exits 125 where buildah exits 1 or 2 (or, in the -+ # case of git, 128, which is a bug in git, but I won't harp on that). ++ # Special case: there's one test that invokes git in such ++ # a way that it exits 128 (which IMO is a bug in git). ++ # podman exits 125 in that case. + case $expected_rc in -+ 1|2|128) expected_rc=125 ;; ++ 128) expected_rc=125 ;; + esac + fi + local cmd_basename=$(basename ${podman_or_buildah}) @@ -97,7 +98,7 @@ index e3087063..b3a8f5ee 100644 # If session is rootless and `buildah mount` is invoked, perform unshare, # since normal user cannot mount a filesystem unless they're in a user namespace along with its own mount namespace. -@@ -262,8 +316,8 @@ function run_buildah() { +@@ -262,8 +317,8 @@ function run_buildah() { retry=$(( retry - 1 )) # stdout is only emitted upon error; this echo is to help a debugger @@ -108,7 +109,7 @@ index e3087063..b3a8f5ee 100644 # without "quotes", multiple lines are glommed together into one if [ -n "$output" ]; then echo "$output" -@@ -595,6 +649,15 @@ function skip_if_no_docker() { +@@ -595,6 +650,15 @@ function skip_if_no_docker() { fi } @@ -125,5 +126,5 @@ index e3087063..b3a8f5ee 100644 daemondir=${TEST_SCRATCH_DIR}/git-daemon mkdir -p ${daemondir}/repo -- -2.35.1 +2.35.3 diff --git a/test/buildah-bud/run-buildah-bud-tests b/test/buildah-bud/run-buildah-bud-tests index eb8de5618..4ff062496 100755 --- a/test/buildah-bud/run-buildah-bud-tests +++ b/test/buildah-bud/run-buildah-bud-tests @@ -93,6 +93,12 @@ fi # From here on out, any error is fatal set -e +# Run sudo early, to refresh the credentials cache. This is a NOP under CI, +# but might be appreciated by developers who run this script, step away +# during the git-checkout-buildah step, then come back twenty minutes later +# to an expired sudo prompt and no tests have run. +sudo --validate + # Before pulling buildah (while still cd'ed to podman repo), try to determine # if this is a PR, and if so if it's a revendoring of buildah. We use this to # try to offer a helpful hint on failure. diff --git a/test/e2e/build_test.go b/test/e2e/build_test.go index dcdd17143..9ecc2f8c6 100644 --- a/test/e2e/build_test.go +++ b/test/e2e/build_test.go @@ -85,7 +85,7 @@ var _ = Describe("Podman build", func() { }) It("podman build with a secret from file and verify if secret file is not leaked into image", func() { - session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/"}) + session := podmanTest.Podman([]string{"build", "-f", "build/secret-verify-leak/Containerfile.with-secret-verify-leak", "-t", "secret-test-leak", "--secret", "id=mysecret,src=build/secret.txt", "build/secret-verify-leak"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(session.OutputToString()).To(ContainSubstring("somesecret")) @@ -178,6 +178,32 @@ var _ = Describe("Podman build", func() { Expect(session).Should(Exit(0)) }) + It("podman build verify explicit cache use with squash-all and --layers", func() { + session := podmanTest.Podman([]string{"build", "--pull-never", "-f", "build/squash/Dockerfile.squash-c", "--squash-all", "--layers", "-t", "test-squash-d:latest", "build/squash"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"inspect", "--format", "{{.RootFS.Layers}}", "test-squash-d"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // Check for one layers + Expect(strings.Fields(session.OutputToString())).To(HaveLen(1)) + + // Second build must use last squashed build from cache + session = podmanTest.Podman([]string{"build", "--pull-never", "-f", "build/squash/Dockerfile.squash-c", "--squash-all", "--layers", "-t", "test", "build/squash"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // Test if entire build is used from cache + Expect(session.OutputToString()).To(ContainSubstring("Using cache")) + + session = podmanTest.Podman([]string{"inspect", "--format", "{{.RootFS.Layers}}", "test-squash-d"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + // Check for one layers + Expect(strings.Fields(session.OutputToString())).To(HaveLen(1)) + + }) + It("podman build Containerfile locations", func() { // Given // Switch to temp dir and restore it afterwards @@ -529,7 +555,7 @@ subdir**` dd := exec.Command("dd", "if=/dev/random", "of="+randomFile, "bs=1G", "count=1") ddSession, err := Start(dd, GinkgoWriter, GinkgoWriter) Expect(err).ToNot(HaveOccurred()) - Eventually(ddSession).Should(Exit(0)) + Eventually(ddSession, "10s", "1s").Should(Exit(0)) // make cwd as context root path Expect(os.Chdir(contextDir)).ToNot(HaveOccurred()) diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index 787178cd3..1da199714 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -676,8 +676,8 @@ var _ = Describe("Podman checkpoint", func() { }) It("podman checkpoint and restore container with root file-system changes using --ignore-rootfs during restore", func() { // Start the container - localRunString := getRunString([]string{"--rm", ALPINE, "top"}) - session := podmanTest.Podman(localRunString) + // test that restore works without network namespace (https://github.com/containers/podman/issues/14389) + session := podmanTest.Podman([]string{"run", "--network=none", "-d", "--rm", ALPINE, "top"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1)) diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go index 552a7c15d..2a9a86729 100644 --- a/test/e2e/kill_test.go +++ b/test/e2e/kill_test.go @@ -128,6 +128,26 @@ var _ = Describe("Podman kill", func() { Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0)) }) + It("podman kill paused container", func() { + ctrName := "testctr" + session := podmanTest.RunTopContainer(ctrName) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + pause := podmanTest.Podman([]string{"pause", ctrName}) + pause.WaitWithDefaultTimeout() + Expect(pause).Should(Exit(0)) + + kill := podmanTest.Podman([]string{"kill", ctrName}) + kill.WaitWithDefaultTimeout() + Expect(kill).Should(Exit(0)) + + inspect := podmanTest.Podman([]string{"inspect", "-f", "{{.State.Status}}", ctrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(Or(Equal("stopped"), Equal("exited"))) + }) + It("podman kill --cidfile", func() { tmpDir, err := ioutil.TempDir("", "") Expect(err).To(BeNil()) diff --git a/test/e2e/login_logout_test.go b/test/e2e/login_logout_test.go index bce8b78c6..3ae130c6d 100644 --- a/test/e2e/login_logout_test.go +++ b/test/e2e/login_logout_test.go @@ -142,7 +142,7 @@ var _ = Describe("Podman login and logout", func() { defer registriesConf.Close() defer os.Remove(registriesConf.Name()) - err = ioutil.WriteFile(registriesConf.Name(), []byte(registriesConfWithSearch), os.ModePerm) + err = ioutil.WriteFile(registriesConf.Name(), registriesConfWithSearch, os.ModePerm) Expect(err).To(BeNil()) // Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go index 4e6dcb8af..14dd6b6b8 100644 --- a/test/e2e/logs_test.go +++ b/test/e2e/logs_test.go @@ -8,6 +8,7 @@ import ( "time" . "github.com/containers/podman/v4/test/utils" + "github.com/containers/storage/pkg/stringid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gexec" @@ -102,12 +103,12 @@ var _ = Describe("Podman logs", func() { It("tail 99 lines: "+log, func() { skipIfJournaldInContainer() - logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) + name := "test1" + logc := podmanTest.Podman([]string{"run", "--name", name, "--log-driver", log, ALPINE, "sh", "-c", "echo podman; echo podman; echo podman"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) - cid := logc.OutputToString() - results := podmanTest.Podman([]string{"logs", "--tail", "99", cid}) + results := podmanTest.Podman([]string{"logs", "--tail", "99", name}) results.WaitWithDefaultTimeout() Expect(results).To(Exit(0)) Expect(results.OutputToStringArray()).To(HaveLen(3)) @@ -116,11 +117,17 @@ var _ = Describe("Podman logs", func() { It("tail 800 lines: "+log, func() { skipIfJournaldInContainer() + // this uses -d so that we do not have 1000 unnecessary lines printed in every test log logc := podmanTest.Podman([]string{"run", "--log-driver", log, "-dt", ALPINE, "sh", "-c", "i=1; while [ \"$i\" -ne 1000 ]; do echo \"line $i\"; i=$((i + 1)); done"}) logc.WaitWithDefaultTimeout() Expect(logc).To(Exit(0)) cid := logc.OutputToString() + // make sure we wait for the container to finish writing its output + wait := podmanTest.Podman([]string{"wait", cid}) + wait.WaitWithDefaultTimeout() + Expect(wait).To(Exit(0)) + results := podmanTest.Podman([]string{"logs", "--tail", "800", cid}) results.WaitWithDefaultTimeout() Expect(results).To(Exit(0)) @@ -364,6 +371,26 @@ var _ = Describe("Podman logs", func() { Expect(results.OutputToString()).To(Equal("stdout")) Expect(results.ErrorToString()).To(Equal("stderr")) }) + + It("podman logs partial log lines: "+log, func() { + skipIfJournaldInContainer() + + cname := "log-test" + content := stringid.GenerateNonCryptoID() + // use printf to print no extra newline + logc := podmanTest.Podman([]string{"run", "--log-driver", log, "--name", cname, ALPINE, "printf", content}) + logc.WaitWithDefaultTimeout() + Expect(logc).To(Exit(0)) + // Important: do not use OutputToString(), this will remove the trailing newline from the output. + // However this test must make sure that there is no such extra newline. + Expect(string(logc.Out.Contents())).To(Equal(content)) + + logs := podmanTest.Podman([]string{"logs", cname}) + logs.WaitWithDefaultTimeout() + Expect(logs).To(Exit(0)) + // see comment above + Expect(string(logs.Out.Contents())).To(Equal(content)) + }) } It("using journald for container with container tag", func() { diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go index a0716c84d..c9ffe6a8d 100644 --- a/test/e2e/network_connect_disconnect_test.go +++ b/test/e2e/network_connect_disconnect_test.go @@ -2,7 +2,6 @@ package integration import ( "os" - "strings" . "github.com/containers/podman/v4/test/utils" "github.com/containers/storage/pkg/stringid" @@ -94,7 +93,7 @@ var _ = Describe("Podman network connect and disconnect", func() { exec2 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"}) exec2.WaitWithDefaultTimeout() Expect(exec2).Should(Exit(0)) - Expect(strings.Contains(exec2.OutputToString(), ns)).To(BeTrue()) + Expect(exec2.OutputToString()).To(ContainSubstring(ns)) dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"}) dis.WaitWithDefaultTimeout() @@ -113,7 +112,12 @@ var _ = Describe("Podman network connect and disconnect", func() { exec3 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"}) exec3.WaitWithDefaultTimeout() Expect(exec3).Should(Exit(0)) - Expect(strings.Contains(exec3.OutputToString(), ns)).To(BeFalse()) + Expect(exec3.OutputToString()).ToNot(ContainSubstring(ns)) + + // make sure stats still works https://github.com/containers/podman/issues/13824 + stats := podmanTest.Podman([]string{"stats", "test", "--no-stream"}) + stats.WaitWithDefaultTimeout() + Expect(stats).Should(Exit(0)) }) It("bad network name in connect should result in error", func() { @@ -206,7 +210,7 @@ var _ = Describe("Podman network connect and disconnect", func() { exec2 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"}) exec2.WaitWithDefaultTimeout() Expect(exec2).Should(Exit(0)) - Expect(strings.Contains(exec2.OutputToString(), ns)).To(BeFalse()) + Expect(exec2.OutputToString()).ToNot(ContainSubstring(ns)) ip := "10.11.100.99" mac := "44:11:44:11:44:11" @@ -235,7 +239,12 @@ var _ = Describe("Podman network connect and disconnect", func() { exec3 := podmanTest.Podman([]string{"exec", "-it", "test", "cat", "/etc/resolv.conf"}) exec3.WaitWithDefaultTimeout() Expect(exec3).Should(Exit(0)) - Expect(strings.Contains(exec3.OutputToString(), ns)).To(BeTrue()) + Expect(exec3.OutputToString()).To(ContainSubstring(ns)) + + // make sure stats works https://github.com/containers/podman/issues/13824 + stats := podmanTest.Podman([]string{"stats", "test", "--no-stream"}) + stats.WaitWithDefaultTimeout() + Expect(stats).Should(Exit(0)) // make sure no logrus errors are shown https://github.com/containers/podman/issues/9602 rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"}) diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index c67a4baed..715455521 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -475,7 +475,7 @@ var _ = Describe("Podman network", func() { defer podmanTest.removeNetwork(netName) Expect(session).Should(Exit(0)) - interval := time.Duration(250 * time.Millisecond) + interval := 250 * time.Millisecond for i := 0; i < 6; i++ { n := podmanTest.Podman([]string{"network", "exists", netName}) n.WaitWithDefaultTimeout() @@ -490,7 +490,7 @@ var _ = Describe("Podman network", func() { top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx}) top.WaitWithDefaultTimeout() Expect(top).Should(Exit(0)) - interval = time.Duration(250 * time.Millisecond) + interval = 250 * time.Millisecond // Wait for the nginx service to be running for i := 0; i < 6; i++ { // Test curl against the container's name @@ -526,7 +526,7 @@ var _ = Describe("Podman network", func() { defer podmanTest.removeNetwork(netName) Expect(session).Should(Exit(0)) - interval := time.Duration(250 * time.Millisecond) + interval := 250 * time.Millisecond for i := 0; i < 6; i++ { n := podmanTest.Podman([]string{"network", "exists", netName}) n.WaitWithDefaultTimeout() @@ -541,7 +541,7 @@ var _ = Describe("Podman network", func() { top := podmanTest.Podman([]string{"run", "-dt", "--name=web", "--network=" + netName, "--network-alias=web1", "--network-alias=web2", nginx}) top.WaitWithDefaultTimeout() Expect(top).Should(Exit(0)) - interval = time.Duration(250 * time.Millisecond) + interval = 250 * time.Millisecond // Wait for the nginx service to be running for i := 0; i < 6; i++ { // Test curl against the container's name 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 216c3357c..61f2b3a1c 100644 --- a/test/e2e/play_kube_test.go +++ b/test/e2e/play_kube_test.go @@ -21,6 +21,7 @@ import ( "github.com/containers/podman/v4/pkg/util" . "github.com/containers/podman/v4/test/utils" "github.com/containers/storage/pkg/stringid" + "github.com/google/uuid" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/format" @@ -3685,4 +3686,150 @@ ENV OPENJ9_JAVA_OPTIONS=%q Expect(usernsInCtr).Should(Exit(0)) Expect(string(usernsInCtr.Out.Contents())).To(Not(Equal(string(initialUsernsConfig)))) }) + + // Check the block devices are exposed inside container + 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 + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + defer os.RemoveAll(devFolder) + + devicePath := fmt.Sprintf("%s/blockdevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "b", "7", "0"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + blockVolume := getHostPathVolume("BlockDevice", devicePath) + + pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Container should be in running state + inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.State.Status}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("running")) + + // Container should have a block device /dev/loop1 + inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.Devices}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(devicePath)) + }) + + // Check the char devices are exposed inside container + 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 + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + defer os.RemoveAll(devFolder) + + devicePath := fmt.Sprintf("%s/chardevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "c", "3", "1"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + charVolume := getHostPathVolume("CharDevice", devicePath) + + pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(0)) + + // Container should be in running state + inspect := podmanTest.Podman([]string{"inspect", "--format", "{{.State.Status}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring("running")) + + // Container should have a block device /dev/loop1 + inspect = podmanTest.Podman([]string{"inspect", "--format", "{{.HostConfig.Devices}}", "testPod-" + defaultCtrName}) + inspect.WaitWithDefaultTimeout() + Expect(inspect).Should(Exit(0)) + Expect(inspect.OutputToString()).To(ContainSubstring(devicePath)) + }) + + It("podman play kube reports error when the device does not exists", func() { + SkipIfRootless("It needs root access to create devices") + + devicePath := "/dev/foodevdir/baddevice" + + blockVolume := getHostPathVolume("BlockDevice", devicePath) + + pod := getPod(withVolume(blockVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + }) + + 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 + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + defer os.RemoveAll(devFolder) + + devicePath := fmt.Sprintf("%s/chardevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "c", "3", "1"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + charVolume := getHostPathVolume("BlockDevice", devicePath) + + pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + }) + + 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 + uuid, err := uuid.NewUUID() + Expect(err).To(BeNil()) + devFolder := fmt.Sprintf("/dev/foodev%x", uuid[:6]) + Expect(os.MkdirAll(devFolder, os.ModePerm)).To(BeNil()) + + devicePath := fmt.Sprintf("%s/blockdevice", devFolder) + mknod := SystemExec("mknod", []string{devicePath, "b", "7", "0"}) + mknod.WaitWithDefaultTimeout() + Expect(mknod).Should(Exit(0)) + + charVolume := getHostPathVolume("CharDevice", devicePath) + + pod := getPod(withVolume(charVolume), withCtr(getCtr(withImage(registry), withCmd(nil), withArg(nil), withVolumeMount(devicePath, false)))) + err = generateKubeYaml("pod", pod, kubeYaml) + Expect(err).To(BeNil()) + + kube := podmanTest.Podman([]string{"play", "kube", kubeYaml}) + kube.WaitWithDefaultTimeout() + Expect(kube).Should(Exit(125)) + }) + }) diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go index dedb1caeb..4919cc670 100644 --- a/test/e2e/pod_create_test.go +++ b/test/e2e/pod_create_test.go @@ -1112,4 +1112,26 @@ 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")) + }) + }) diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index ab204992c..20794a29c 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -125,6 +125,29 @@ var _ = Describe("Podman pod create", func() { session = podmanTest.Podman([]string{"run", fedoraMinimal, "curl", "-f", "localhost"}) session.WaitWithDefaultTimeout() Expect(session).To(ExitWithError()) + + session = podmanTest.Podman([]string{"pod", "create", "--network", "host"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"run", "--name", "hostCtr", "--pod", session.OutputToString(), ALPINE, "readlink", "/proc/self/ns/net"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + ns := SystemExec("readlink", []string{"/proc/self/ns/net"}) + ns.WaitWithDefaultTimeout() + Expect(ns).Should(Exit(0)) + netns := ns.OutputToString() + Expect(netns).ToNot(BeEmpty()) + + Expect(session.OutputToString()).To(Equal(netns)) + + // Sanity Check for podman inspect + session = podmanTest.Podman([]string{"inspect", "--format", "'{{.NetworkSettings.SandboxKey}}'", "hostCtr"}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + Expect(session.OutputToString()).Should(Equal("''")) // no network path... host + }) It("podman pod correctly sets up IPCNS", func() { 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_networking_test.go b/test/e2e/run_networking_test.go index c9990b70f..4081ec45b 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -381,7 +381,7 @@ EXPOSE 2004-2005/tcp`, ALPINE) session := podmanTest.Podman([]string{"run", "-dt", "-p", fmt.Sprintf("%d:%d", port1, port2), ALPINE, "/bin/sh"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) - results := SystemExec("iptables", []string{"-t", "nat", "-L"}) + results := SystemExec("iptables", []string{"-t", "nat", "-nvL"}) Expect(results).Should(Exit(0)) Expect(results.OutputToString()).To(ContainSubstring(fmt.Sprintf("%d", port2))) @@ -731,7 +731,7 @@ EXPOSE 2004-2005/tcp`, ALPINE) linkAttr.Name = name m, err := net.ParseMAC(mac) Expect(err).To(BeNil()) - linkAttr.HardwareAddr = net.HardwareAddr(m) + linkAttr.HardwareAddr = m eth := &netlink.Dummy{LinkAttrs: linkAttr} err = netlink.LinkAdd(eth) Expect(err).To(BeNil()) 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_test.go b/test/e2e/run_test.go index 182ae1888..828e92170 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/containers/common/pkg/cgroups" + "github.com/containers/podman/v4/libpod/define" "github.com/containers/podman/v4/pkg/rootless" . "github.com/containers/podman/v4/test/utils" "github.com/containers/storage/pkg/stringid" @@ -286,19 +287,20 @@ var _ = Describe("Podman run", func() { result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) conData := result.InspectContainerToJSON() - Expect(conData[0]).To(HaveField("Path", "/dev/init")) + Expect(conData[0]).To(HaveField("Path", define.ContainerInitPath)) Expect(conData[0].Config.Annotations).To(HaveKeyWithValue("io.podman.annotations.init", "TRUE")) }) It("podman run a container with --init and --init-path", func() { - session := podmanTest.Podman([]string{"run", "--name", "test", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) + // Also bind-mount /dev (#14251). + session := podmanTest.Podman([]string{"run", "-v", "/dev:/dev", "--name", "test", "--init", "--init-path", "/usr/libexec/podman/catatonit", ALPINE, "ls"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) result := podmanTest.Podman([]string{"inspect", "test"}) result.WaitWithDefaultTimeout() Expect(result).Should(Exit(0)) conData := result.InspectContainerToJSON() - Expect(conData[0]).To(HaveField("Path", "/dev/init")) + Expect(conData[0]).To(HaveField("Path", define.ContainerInitPath)) Expect(conData[0].Config.Annotations).To(HaveKeyWithValue("io.podman.annotations.init", "TRUE")) }) diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go index 3bef889b7..1c0480407 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() diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go index 897e49ef7..7a1fb0fc2 100644 --- a/test/e2e/save_test.go +++ b/test/e2e/save_test.go @@ -226,13 +226,17 @@ default-docker: }) It("podman save --multi-image-archive (untagged images)", func() { - // Refer to images via ID instead of tag. - session := podmanTest.Podman([]string{"images", "--format", "{{.ID}}"}) + // #14468: to make execution time more predictable, save at + // most three images and sort them by size. + session := podmanTest.Podman([]string{"images", "--sort", "size", "--format", "{{.ID}}"}) session.WaitWithDefaultTimeout() Expect(session).Should(Exit(0)) ids := session.OutputToStringArray() Expect(len(ids)).To(BeNumerically(">", 1), "We need to have *some* images to save") + if len(ids) > 3 { + ids = ids[:3] + } multiImageSave(podmanTest, ids) }) }) diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index 64677ba54..d37d8fd1a 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -455,7 +455,6 @@ registries = ['{{.Host}}:{{.Port}}']` }) It("podman search with wildcards", func() { - Skip("FIXME: search on registry.redhat.io is broken (Dec 16 '21)") search := podmanTest.Podman([]string{"search", "registry.redhat.io/*openshift*"}) search.WaitWithDefaultTimeout() Expect(search).Should(Exit(0)) diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go index b43a81cd3..3000a819f 100644 --- a/test/e2e/stats_test.go +++ b/test/e2e/stats_test.go @@ -236,4 +236,15 @@ var _ = Describe("Podman stats", func() { Expect(customLimit).To(BeNumerically("<", defaultLimit)) }) + + It("podman stats with a container that is not running", func() { + ctr := "created_container" + session := podmanTest.Podman([]string{"create", "--name", ctr, ALPINE}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + + session = podmanTest.Podman([]string{"stats", "--no-stream", ctr}) + session.WaitWithDefaultTimeout() + Expect(session).Should(Exit(0)) + }) }) diff --git a/test/e2e/system_df_test.go b/test/e2e/system_df_test.go index ba4a40ab4..5a23fc0bb 100644 --- a/test/e2e/system_df_test.go +++ b/test/e2e/system_df_test.go @@ -66,7 +66,7 @@ var _ = Describe("podman system df", func() { images := strings.Fields(session.OutputToStringArray()[1]) containers := strings.Fields(session.OutputToStringArray()[2]) volumes := strings.Fields(session.OutputToStringArray()[3]) - Expect(images[1]).To(Equal(string(totImages)), "total images expected") + Expect(images[1]).To(Equal(totImages), "total images expected") 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") diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go index 0bf5acbf1..499283cab 100644 --- a/test/e2e/volume_create_test.go +++ b/test/e2e/volume_create_test.go @@ -110,15 +110,24 @@ var _ = Describe("Podman volume create", func() { Expect(session.OutputToString()).To(ContainSubstring("hello")) }) - It("podman import volume should fail", func() { + It("podman import/export volume should fail", func() { // try import on volume or source which does not exists - if podmanTest.RemoteTest { - Skip("Volume export check does not work with a remote client") - } + SkipIfRemote("Volume export check does not work with a remote client") session := podmanTest.Podman([]string{"volume", "import", "notfound", "notfound.tar"}) session.WaitWithDefaultTimeout() Expect(session).To(ExitWithError()) + Expect(session.ErrorToString()).To(ContainSubstring("open notfound.tar: no such file or directory")) + + session = podmanTest.Podman([]string{"volume", "import", "notfound", "-"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound")) + + session = podmanTest.Podman([]string{"volume", "export", "notfound"}) + session.WaitWithDefaultTimeout() + Expect(session).To(ExitWithError()) + Expect(session.ErrorToString()).To(ContainSubstring("no such volume notfound")) }) It("podman create volume with bad volume option", func() { diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 5757d51dc..1356c99a0 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -34,10 +34,16 @@ function check_help() { # has no ' [options]' is "$usage " " $command_string .*" "Usage string matches command" + # Strip off the leading command string; we no longer need it + usage=$(sed -e "s/^ $command_string \?//" <<<"$usage") + # If usage ends in '[command]', recurse into subcommands - if expr "$usage" : '.*\[command\]$' >/dev/null; then + if expr "$usage" : '\[command\]' >/dev/null; then found[subcommands]=1 - check_help "$@" $cmd + # (except for 'podman help', which is a special case) + if [[ $cmd != "help" ]]; then + check_help "$@" $cmd + fi continue fi @@ -49,10 +55,26 @@ function check_help() { assert "$usage" !~ '[A-Z].*\[option' \ "'options' must precede arguments in usage" + # Strip off '[options]' but remember if we've seen it. + local has_options= + if [[ $usage =~ \[options\] ]]; then + has_options=1 + usage=$(sed -e 's/^\[options\] \?//' <<<"$usage") + fi + + # From this point on, remaining argument descriptions must be UPPER CASE + # e.g., 'podman cmd [options] arg' or 'podman cmd [arg]' are invalid. + assert "$usage" !~ '[a-z]' \ + "$command_string: argument names must be UPPER CASE" + + # It makes no sense to have an optional arg followed by a mandatory one + assert "$usage" !~ '\[.*\] [A-Z]' \ + "$command_string: optional args must be _after_ required ones" + # Cross-check: if usage includes '[options]', there must be a # longer 'Options:' section in the full --help output; vice-versa, # if 'Options:' is in full output, usage line must have '[options]'. - if expr "$usage" : '.*\[option' >/dev/null; then + if [[ $has_options ]]; then if ! expr "$full_help" : ".*Options:" >/dev/null; then die "$command_string: Usage includes '[options]' but has no 'Options:' subsection" fi @@ -95,9 +117,7 @@ function check_help() { fi # If usage has required arguments, try running without them. - # The expression here is 'first capital letter is not in [BRACKETS]'. - # It is intended to handle 'podman foo [options] ARG' but not ' [ARG]'. - if expr "$usage" : '[^A-Z]\+ [A-Z]' >/dev/null; then + if expr "$usage" : '[A-Z]' >/dev/null; then # Exceptions: these commands don't work rootless if is_rootless; then # "pause is not supported for rootless containers" @@ -126,25 +146,15 @@ function check_help() { # the required args, then invoke with one extra. We should get a # usage error. if ! expr "$usage" : ".*\.\.\."; then - # "podman help" can take infinite args, so skip that one - if [ "$cmd" != "help" ]; then - # Get the args part of the command line; this should be - # everything from the first CAPITAL LETTER onward. We - # don't actually care about the letter itself, so just - # make it 'X'. And we don't care about [OPTIONAL] brackets - # either. What we do care about is stuff like 'IMAGE | CTR' - # which is actually one argument; convert to 'IMAGE-or-CTR' - local rhs=$(sed -e 's/^[^A-Z]\+[A-Z]/X/' -e 's/ | /-or-/g' <<<"$usage") - local n_args=$(wc -w <<<"$rhs") - - run_podman '?' "$@" $cmd $(seq --format='x%g' 0 $n_args) - is "$status" 125 \ - "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected this exit status" - is "$output" "Error:.* \(takes no arguments\|requires exactly $n_args arg\|accepts at most\|too many arguments\|accepts $n_args arg(s), received\|accepts between .* and .* arg(s), received \)" \ - "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected one of these error messages" + local n_args=$(wc -w <<<"$usage") - found[fixed_args]=1 - fi + run_podman '?' "$@" $cmd $(seq --format='x%g' 0 $n_args) + is "$status" 125 \ + "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected this exit status" + is "$output" "Error:.* \(takes no arguments\|requires exactly $n_args arg\|accepts at most\|too many arguments\|accepts $n_args arg(s), received\|accepts between .* and .* arg(s), received \)" \ + "'$usage' indicates a maximum of $n_args args. I invoked it with more, and expected one of these error messages" + + found[fixed_args]=1 fi count=$(expr $count + 1) diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 283c3aea9..241831257 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -855,4 +855,15 @@ EOF run_podman rmi $test_image } +@test "podman create --security-opt" { + run_podman create --security-opt no-new-privileges=true $IMAGE + run_podman rm $output + run_podman create --security-opt no-new-privileges:true $IMAGE + run_podman rm $output + run_podman create --security-opt no-new-privileges=false $IMAGE + run_podman rm $output + run_podman create --security-opt no-new-privileges $IMAGE + run_podman rm $output +} + # vim: filetype=sh diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats index 7addbd88e..2735d2afd 100644 --- a/test/system/060-mount.bats +++ b/test/system/060-mount.bats @@ -50,6 +50,10 @@ load helpers run_podman image mount $IMAGE mount_path="$output" + # Make sure that `mount -a` prints a table + run_podman image mount -a + is "$output" "$IMAGE .*$mount_path" + test -d $mount_path # Image is custom-built and has a file containing the YMD tag. Check it. @@ -62,8 +66,8 @@ load helpers run_podman image mount is "$output" "$IMAGE *$mount_path" "podman image mount with no args" - # Clean up - run_podman image umount $IMAGE + # Clean up: -f since we mounted it twice + run_podman image umount -f $IMAGE is "$output" "$iid" "podman image umount: image ID of what was umounted" run_podman image umount $IMAGE 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/120-load.bats b/test/system/120-load.bats index 45e0b3362..5a7f63b43 100644 --- a/test/system/120-load.bats +++ b/test/system/120-load.bats @@ -121,7 +121,7 @@ verify_iid_and_name() { run_podman untag $IMAGE $newname run_podman image scp -q ${notme}@localhost::$newname - expect="Loaded image(s): $newname" + expect="Loaded image: $newname" is "$output" "$expect" "-q silences output" # Confirm that we have it, and that its digest matches our original diff --git a/test/system/160-volumes.bats b/test/system/160-volumes.bats index 5b0460723..797883ec6 100644 --- a/test/system/160-volumes.bats +++ b/test/system/160-volumes.bats @@ -411,4 +411,43 @@ NeedsChown | true fi } +@test "podman --image-volume" { + tmpdir=$PODMAN_TMPDIR/volume-test + mkdir -p $tmpdir + containerfile=$tmpdir/Containerfile + cat >$containerfile <<EOF +FROM $IMAGE +VOLUME /data +EOF + fs=$(stat -f -c %T .) + run_podman build -t volume_image $tmpdir + + containersconf=$tmpdir/containers.conf + cat >$containersconf <<EOF +[engine] +image_volume_mode="tmpfs" +EOF + + run_podman run --image-volume tmpfs --rm volume_image stat -f -c %T /data + is "$output" "tmpfs" "Should be tmpfs" + + run_podman 1 run --image-volume ignore --rm volume_image stat -f -c %T /data + is "$output" "stat: can't read file system information for '/data': No such file or directory" "Should fail with /data does not exists" + + CONTAINERS_CONF="$containersconf" run_podman run --rm volume_image stat -f -c %T /data + is "$output" "tmpfs" "Should be tmpfs" + + CONTAINERS_CONF="$containersconf" run_podman run --image-volume bind --rm volume_image stat -f -c %T /data + assert "$output" != "tmpfs" "Should match hosts $fs" + + CONTAINERS_CONF="$containersconf" run_podman run --image-volume tmpfs --rm volume_image stat -f -c %T /data + is "$output" "tmpfs" "Should be tmpfs" + + CONTAINERS_CONF="$containersconf" run_podman 1 run --image-volume ignore --rm volume_image stat -f -c %T /data + is "$output" "stat: can't read file system information for '/data': No such file or directory" "Should fail with /data does not exists" + + run_podman rm --all --force -t 0 + run_podman image rm --force localhost/volume_image +} + # vim: filetype=sh diff --git a/test/system/170-run-userns.bats b/test/system/170-run-userns.bats index b80351902..84788a7f4 100644 --- a/test/system/170-run-userns.bats +++ b/test/system/170-run-userns.bats @@ -38,10 +38,12 @@ function _require_crun() { @test "rootful pod with custom ID mapping" { skip_if_rootless "does not work rootless - rootful feature" - skip_if_remote "remote --uidmap is broken (see #14233)" random_pod_name=$(random_string 30) run_podman pod create --uidmap 0:200000:5000 --name=$random_pod_name run_podman pod start $random_pod_name + run_podman pod inspect --format '{{.InfraContainerID}}' $random_pod_name + run podman inspect --format '{{.HostConfig.IDMappings.UIDMap}}' $output + is "$output" ".*0:200000:5000" "UID Map Successful" # Remove the pod and the pause image run_podman pod rm $random_pod_name @@ -109,15 +111,30 @@ EOF } @test "podman userns=nomap" { - skip_if_not_rootless "--userns=nomap only works in rootless mode" - ns_user=$(id -un) - baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:) - test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}" + if is_rootless; then + ns_user=$(id -un) + baseuid=$(egrep "${ns_user}:" /etc/subuid | cut -f2 -d:) + test ! -z ${baseuid} || skip "no IDs allocated for user ${ns_user}" + + test_name="test_$(random_string 12)" + run_podman run -d --userns=nomap $IMAGE sleep 100 + cid=${output} + run_podman top ${cid} huser + is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID" + run_podman rm -t 0 --force ${cid} + else + run_podman 125 run -d --userns=nomap $IMAGE sleep 100 + is "${output}" "Error: nomap is only supported in rootless mode" "Container should fail to start since nomap is not suppored in rootful mode" + fi +} - test_name="test_$(random_string 12)" - run_podman run -d --userns=nomap $IMAGE sleep 100 - cid=${output} - run_podman top ${cid} huser - is "${output}" "HUSER.*${baseuid}" "Container should start with baseuid from /etc/subuid not user UID" - run_podman rm -t 0 --force ${cid} +@test "podman userns=keep-id" { + if is_rootless; then + user=$(id -u) + run_podman run --rm --userns=keep-id $IMAGE id -u + is "${output}" "$user" "Container should run as the current user" + else + run_podman 125 run --rm --userns=keep-id $IMAGE id -u + is "${output}" "Error: keep-id is only supported in rootless mode" "Container should fail to start since keep-id is not suppored in rootful mode" + fi } diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index 4250f2680..404ad67ec 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -335,8 +335,15 @@ EOF is "$output" ".*Invalid kernel namespace to share: bogus. Options are: cgroup, ipc, net, pid, uts or none" \ "pod test for bogus --share option" run_podman pod create --share ipc --name $pod_name + run_podman pod inspect $pod_name --format "{{.SharedNamespaces}}" + is "$output" "[ipc]" run_podman run --rm --pod $pod_name --hostname foobar $IMAGE hostname is "$output" "foobar" "--hostname should work with non share UTS namespace" + run_podman pod create --share +pid --replace --name $pod_name + run_podman pod inspect $pod_name --format "{{.SharedNamespaces}}" + for ns in uts pid ipc net; do + is "$output" ".*$ns" + done } @test "podman pod create --pod new:$POD --hostname" { @@ -387,20 +394,20 @@ EOF is "$output" "false" "Default network sharing should be false" run_podman pod rm test - run_podman pod create --name test --share ipc --network private + run_podman pod create --share ipc --network private test run_podman pod inspect test --format {{.InfraConfig.HostNetwork}} is "$output" "false" "Private network sharing with only ipc should be false" run_podman pod rm test - run_podman pod create --name test --share net --network private - run_podman pod inspect test --format {{.InfraConfig.HostNetwork}} + local name="$(random_string 10 | tr A-Z a-z)" + run_podman pod create --name $name --share net --network private + run_podman pod inspect $name --format {{.InfraConfig.HostNetwork}} is "$output" "false" "Private network sharing with only net should be false" - run_podman pod rm test - run_podman pod create --name test --share net --network host - run_podman pod inspect test --format {{.InfraConfig.HostNetwork}} + run_podman pod create --share net --network host --replace $name + run_podman pod inspect $name --format {{.InfraConfig.HostNetwork}} is "$output" "true" "Host network sharing with only net should be true" - run_podman pod rm test + run_podman pod rm $name run_podman pod create --name test --share ipc --network host run_podman pod inspect test --format {{.InfraConfig.HostNetwork}} diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index 567fa89c1..110d425d2 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -80,12 +80,6 @@ function service_cleanup() { run_podman logs $cname is "$output" ".*WAITING.*" "running is waiting for signal" - # Exercise `podman auto-update`. - # TODO: this will at least run auto-update code but won't perform an update - # since the image didn't change. We need to improve on that and run - # an image from a local registry instead. - run_podman auto-update - # All good. Stop service, clean up. # Also make sure the service is in the `inactive` state (see #11304). service_cleanup inactive diff --git a/test/system/255-auto-update.bats b/test/system/255-auto-update.bats index 6cdae2ada..6cee939fb 100644 --- a/test/system/255-auto-update.bats +++ b/test/system/255-auto-update.bats @@ -135,15 +135,27 @@ function _confirm_update() { # This test can fail in dev. environment because of SELinux. # quick fix: chcon -t container_runtime_exec_t ./bin/podman @test "podman auto-update - label io.containers.autoupdate=image" { + since=$(date --iso-8601=seconds) + run_podman auto-update + is "$output" "" + run_podman events --filter type=system --since $since --stream=false + is "$output" "" + generate_service alpine image _wait_service_ready container-$cname.service + since=$(date --iso-8601=seconds) run_podman auto-update --dry-run --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,pending,registry.*" "Image update is pending." + run_podman events --filter type=system --since $since --stream=false + is "$output" ".* system auto-update" + since=$(date --iso-8601=seconds) run_podman auto-update --format "{{.Unit}},{{.Image}},{{.Updated}},{{.Policy}}" is "$output" "Trying to pull.*" "Image is updated." is "$output" ".*container-$cname.service,quay.io/libpod/alpine:latest,true,registry.*" "Image is updated." + run_podman events --filter type=system --since $since --stream=false + is "$output" ".* system auto-update" _confirm_update $cname $ori_image } diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 3db0804d1..92aabae32 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 diff --git a/test/system/520-checkpoint.bats b/test/system/520-checkpoint.bats index c16a8c35d..7f60f01b3 100644 --- a/test/system/520-checkpoint.bats +++ b/test/system/520-checkpoint.bats @@ -170,4 +170,34 @@ function teardown() { # FIXME: test --leave-running +@test "podman checkpoint --file-locks" { + action='flock test.lock sh -c "while [ -e /wait ];do sleep 0.5;done;for i in 1 2 3;do echo \$i;sleep 0.5;done"' + run_podman run -d $IMAGE sh -c "touch /wait; touch test.lock; echo READY; $action & $action & wait" + local cid="$output" + + # Wait for container to start emitting output + wait_for_ready $cid + + # Checkpoint, and confirm via inspect + run_podman container checkpoint --file-locks $cid + is "$output" "$cid" "podman container checkpoint" + + run_podman container inspect \ + --format '{{.State.Status}}:{{.State.Running}}:{{.State.Paused}}:{{.State.Checkpointed}}' $cid + is "$output" "exited:false:false:true" "State. Status:Running:Pause:Checkpointed" + + # Restart immediately and confirm state + run_podman container restore --file-locks $cid + is "$output" "$cid" "podman container restore" + + # Signal the container to continue; this is where the 1-2-3s will come from + run_podman exec $cid rm /wait + + # Wait for the container to stop + run_podman wait $cid + + run_podman logs $cid + trim=$(sed -z -e 's/[\r\n]\+//g' <<<"$output") + is "$trim" "READY123123" "File lock restored" +} # vim: filetype=sh diff --git a/test/system/600-completion.bats b/test/system/600-completion.bats index 018e95e78..cb4a2c5f8 100644 --- a/test/system/600-completion.bats +++ b/test/system/600-completion.bats @@ -8,6 +8,16 @@ load helpers +function setup() { + # $PODMAN may be a space-separated string, e.g. if we include a --url. + local -a podman_as_array=($PODMAN) + # __completeNoDesc must be the first arg if we running the completion cmd + # set the var for the run_completion function + PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}" + + basic_setup +} + # Returns true if we are able to podman-pause function _can_pause() { # Even though we're just trying completion, not an actual unpause, @@ -88,8 +98,14 @@ function check_shell_completion() { continue 2 fi + name=$random_container_name + # special case podman cp suggest containers names with a colon + if [[ $cmd = "cp" ]]; then + name="$name:" + fi + run_completion "$@" $cmd "${extra_args[@]}" "" - is "$output" ".*-$random_container_name${nl}" \ + is "$output" ".*-$name${nl}" \ "$* $cmd: actual container listed in suggestions" match=true @@ -175,7 +191,7 @@ function check_shell_completion() { _check_completion_end NoSpace else _check_completion_end Default - assert "${#lines[@]}" -eq 2 "$* $cmd: Suggestions are in the output" + _check_no_suggestions fi ;; @@ -205,16 +221,7 @@ function check_shell_completion() { if [[ ! ${args##* } =~ "..." ]]; then run_completion "$@" $cmd "${extra_args[@]}" "" _check_completion_end NoFileComp - if [ ${#lines[@]} -gt 2 ]; then - # checking for line count is not enough since we may include additional debug output - # lines starting with [Debug] are allowed - i=0 - length=$(( ${#lines[@]} - 2 )) - while [[ i -lt length ]]; do - assert "${lines[$i]:0:7}" == "[Debug]" "Suggestions are in the output" - i=$(( i + 1 )) - done - fi + _check_no_suggestions fi done @@ -231,6 +238,24 @@ function _check_completion_end() { is "${lines[-1]}" "Completion ended with directive: ShellCompDirective$1" "Completion has wrong ShellCompDirective set" } +# Check that there are no suggestions in the output. +# We could only check stdout and not stderr but this is not possible with bats. +# By default we always have two extra lines at the end for the ShellCompDirective. +# Then we could also have other extra lines for debugging, they will always start +# with [Debug], e.g. `[Debug] [Error] no container with name or ID "t12" found: no such container`. +function _check_no_suggestions() { + if [ ${#lines[@]} -gt 2 ]; then + # Checking for line count is not enough since we may include additional debug output. + # Lines starting with [Debug] are allowed. + local i=0 + length=$((${#lines[@]} - 2)) + while [[ i -lt length ]]; do + assert "${lines[$i]:0:7}" == "[Debug]" "Unexpected non-Debug output line: ${lines[$i]}" + i=$((i + 1)) + done + fi +} + @test "podman shell completion test" { @@ -280,11 +305,6 @@ function _check_completion_end() { # create secret run_podman secret create $random_secret_name $secret_file - # $PODMAN may be a space-separated string, e.g. if we include a --url. - local -a podman_as_array=($PODMAN) - # __completeNoDesc must be the first arg if we running the completion cmd - PODMAN_COMPLETION="${podman_as_array[0]} __completeNoDesc ${podman_as_array[@]:1}" - # Called with no args -- start with 'podman --help'. check_shell_completion() will # recurse for any subcommands. check_shell_completion @@ -316,3 +336,51 @@ function _check_completion_end() { done <<<"$output" } + +@test "podman shell completion for paths in container/image" { + skip_if_remote "mounting via remote does not work" + for cmd in create run; do + run_completion $cmd $IMAGE "" + assert "$output" =~ ".*^/etc/\$.*" "etc directory suggested (cmd: podman $cmd)" + assert "$output" =~ ".*^/home/\$.*" "home directory suggested (cmd: podman $cmd)" + assert "$output" =~ ".*^/root/\$.*" "root directory suggested (cmd: podman $cmd)" + + # check completion for subdirectory + run_completion $cmd $IMAGE "/etc" + # It should be safe to assume the os-release file always exists in $IMAGE + assert "$output" =~ ".*^/etc/os-release\$.*" "/etc files suggested (cmd: podman $cmd /etc)" + # check completion for partial file name + run_completion $cmd $IMAGE "/etc/os-" + assert "$output" =~ ".*^/etc/os-release\$.*" "/etc files suggested (cmd: podman $cmd /etc/os-)" + + # check completion with relative path components + # It is important the we will still use the image root and not escape to the host + run_completion $cmd $IMAGE "../../" + assert "$output" =~ ".*^../../etc/\$.*" "relative etc directory suggested (cmd: podman $cmd ../../)" + assert "$output" =~ ".*^../../home/\$.*" "relative home directory suggested (cmd: podman $cmd ../../)" + done + + random_name=$(random_string 30) + random_file=$(random_string 30) + run_podman run --name $random_name $IMAGE sh -c "touch /tmp/$random_file && touch /tmp/${random_file}2 && mkdir /emptydir" + + # check completion for podman cp + run_completion cp "" + assert "$output" =~ ".*^$random_name\:\$.*" "podman cp suggest container names" + + run_completion cp "$random_name:" + assert "$output" =~ ".*^$random_name\:/etc/\$.*" "podman cp suggest paths in container" + + run_completion cp "$random_name:/tmp" + assert "$output" =~ ".*^$random_name\:/tmp/$random_file\$.*" "podman cp suggest custom file in container" + + run_completion cp "$random_name:/tmp/$random_file" + assert "$output" =~ ".*^$random_name\:/tmp/$random_file\$.*" "podman cp suggest /tmp/$random_file file in container" + assert "$output" =~ ".*^$random_name\:/tmp/${random_file}2\$.*" "podman cp suggest /tmp/${random_file}2 file in container" + + run_completion cp "$random_name:/emptydir" + assert "$output" =~ ".*^$random_name\:/emptydir/\$.*ShellCompDirectiveNoSpace" "podman cp suggest empty dir with no space directive (:2)" + + # cleanup container + run_podman rm $random_name +} diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 6868f2691..fe9e971fb 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -397,25 +397,25 @@ function _ensure_pod_state() { for i in {0..5}; do run_podman pod inspect $1 --format "{{.State}}" if [[ $output == "$2" ]]; then - break + return fi sleep 0.5 done - is "$output" "$2" "unexpected pod state" + die "Timed out waiting for pod $1 to enter state $2" } # Wait for the container's (1st arg) running state (2nd arg) function _ensure_container_running() { - for i in {0..5}; do + for i in {0..20}; do run_podman container inspect $1 --format "{{.State.Running}}" if [[ $output == "$2" ]]; then - break + return fi sleep 0.5 done - is "$output" "$2" "unexpected pod state" + die "Timed out waiting for container $1 to enter state running=$2" } ########################### diff --git a/test/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 |