From 0a2eb7b1857907f065a48a07a9a3096fa3cc5f77 Mon Sep 17 00:00:00 2001
From: Ed Santiago <santiago@redhat.com>
Date: Tue, 14 Dec 2021 08:41:26 -0700
Subject: apiv2 tests: refactor complicated curls

Some months ago, apiv2 tests got added that needed new
functionality: passing a tarball to the remote server.
There was no mechanism to do so in the 't' helper, so
these tests used complicated (and actually not-really-
working) curl commands.

This PR introduces and documents a new usage of 't', in
which passing an argument ending in '.tar' adds the
right magic syntax (--data-binary @PATH) to the existing
curl. This lets us use all standard 't' checks, making
for simpler tests and in the process fixing some bugs.

Also: drive-by fix of a typo bug in the networks test.

Also: set CONTAINERS_REGISTRIES_CONF when starting server
and when running direct podman, to avoid docker.io throttling.

Signed-off-by: Ed Santiago <santiago@redhat.com>
---
 test/apiv2/10-images.at   | 90 ++++++++++-------------------------------------
 test/apiv2/35-networks.at |  2 +-
 test/apiv2/README.md      |  6 ++++
 test/apiv2/test-apiv2     | 31 +++++++++++-----
 4 files changed, 48 insertions(+), 81 deletions(-)

(limited to 'test')

diff --git a/test/apiv2/10-images.at b/test/apiv2/10-images.at
index 115332d0c..f849fc33c 100644
--- a/test/apiv2/10-images.at
+++ b/test/apiv2/10-images.at
@@ -171,84 +171,32 @@ function cleanBuildTest() {
 }
 CONTAINERFILE_TAR="${TMPD}/containerfile.tar"
 cat > $TMPD/containerfile << EOF
-FROM quay.io/libpod/alpine_labels:latest
+FROM $IMAGE
 EOF
 tar --format=posix -C $TMPD -cvf ${CONTAINERFILE_TAR} containerfile &> /dev/null
 
-curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
-    -H "content-type: application/x-tar" \
-    --dump-header "${TMPD}/headers.txt" \
-    -o "${TMPD}/response.txt" \
-    "http://$HOST:$PORT/v1.40/libpod/build?dockerfile=containerfile" &> /dev/null
-
-BUILD_TEST_ERROR=""
-
-if ! grep -q '200 OK' "${TMPD}/headers.txt"; then
-    echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/x-tar)"
-    BUILD_TEST_ERROR="1"
-fi
-
-if ! grep -q 'quay.io/libpod/alpine_labels' "${TMPD}/response.txt"; then
-    echo -e "${red}NOK: Image build from tar failed image name not in response"
-    BUILD_TEST_ERROR="1"
-fi
-
-curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
-    -H "content-type: application/tar" \
-    --dump-header "${TMPD}/headers.txt" \
-    -o "${TMPD}/response.txt" \
-    "http://$HOST:$PORT/v1.40/build?dockerfile=containerfile&q=true" &> /dev/null
-if ! grep -q '200 OK' "${TMPD}/headers.txt"; then
-    echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/tar)"
-    BUILD_TEST_ERROR="1"
-fi
-if grep -E "\"[0-9a-f]{64}\\\n\"" $(jq .stream "${TMPD}/response.txt"); then
-    echo -e "${red} quiet-mode should only send image ID"
-    BUILD_TEST_ERROR="1"
-fi
-
-# Yes, this is very un-RESTful re: Content-Type header ignored when compatibility endpoint used
-# See https://github.com/containers/podman/issues/11012
-curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
-    -H "content-type: application/json" \
-    --dump-header "${TMPD}/headers.txt" \
-    -o /dev/null \
-    "http://$HOST:$PORT/v1.40/build?dockerfile=containerfile" &> /dev/null
-if ! grep -q '200 OK' "${TMPD}/headers.txt"; then
-    echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/tar)"
-    BUILD_TEST_ERROR="1"
-fi
-
-curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
-    -H "content-type: application/json" \
-    --dump-header "${TMPD}/headers.txt" \
-    -o /dev/null \
-    "http://$HOST:$PORT/v1.40/libpod/build?dockerfile=containerfile" &> /dev/null
-if ! grep -q '400 Bad Request' "${TMPD}/headers.txt"; then
-    echo -e "${red}NOK: Image build should have failed with 400 (wrong Content-Type)"
-    BUILD_TEST_ERROR="1"
-fi
-
-curl -XPOST --data-binary @<(cat $CONTAINERFILE_TAR) \
-    -H "content-type: application/tar" \
-    --dump-header "${TMPD}/headers.txt" \
-    -o "${TMPD}/response.txt" \
-    "http://$HOST:$PORT/v1.40/build?dockerfile=containerfile" &> /dev/null
-if ! grep -q '200 OK' "${TMPD}/headers.txt"; then
-    echo -e "${red}NOK: Image build from tar failed response was not 200 OK (application/tar)"
-    BUILD_TEST_ERROR="1"
-fi
-if ! grep -qP '^{"aux":{"ID":"sha256:[0-9a-f]{64}"}}$' "${TMPD}/response.txt"; then
-    echo -e "${red}NOK: Image build response does not contain ID"
-    BUILD_TEST_ERROR="1"
-fi
+t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR 200 \
+  .stream~"STEP 1/1: FROM $IMAGE"
+
+# With -q, all we should get is image ID. Test both libpod & compat endpoints.
+t POST "libpod/build?dockerfile=containerfile&q=true" $CONTAINERFILE_TAR 200 \
+  .stream~'^[0-9a-f]\{64\}$'
+t POST "build?dockerfile=containerfile&q=true" $CONTAINERFILE_TAR 200 \
+  .stream~'^[0-9a-f]\{64\}$'
+
+# Override content-type and confirm that libpod rejects, but compat accepts
+t POST "libpod/build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 400 \
+  .cause='Content-Type: application/json is not supported. Should be "application/x-tar"'
+t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR application/json 200 \
+  .stream~"STEP 1/1: FROM $IMAGE"
+
+# PR #12091: output from compat API must now include {"aux":{"ID":"sha..."}}
+t POST "build?dockerfile=containerfile" $CONTAINERFILE_TAR 200 \
+  '.aux|select(has("ID")).ID~^sha256:[0-9a-f]\{64\}$'
 
 t POST libpod/images/prune 200
 t POST libpod/images/prune 200 length=0 []
 
 cleanBuildTest
-if [[ "${BUILD_TEST_ERROR}" ]]; then
-    exit 1
-fi
 
 # vim: filetype=sh
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index 713f677fa..0e2389bd5 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -7,7 +7,7 @@ t GET networks/non-existing-network 404 \
   .cause='network not found'
 
 t POST libpod/networks/create name='"network1"' 200 \
-  .name=network1
+  .name=network1 \
   .created~[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}.* \
 
 # --data '{"name":"network2","subnets":[{"subnet":"10.10.254.0/24"}],"Labels":{"abc":"val"}}'
diff --git a/test/apiv2/README.md b/test/apiv2/README.md
index 19727cec7..63d1f5b13 100644
--- a/test/apiv2/README.md
+++ b/test/apiv2/README.md
@@ -60,6 +60,12 @@ of POST parameters in the form 'key=value', separated by spaces:
      t POST myentrypoint name=$name badparam='["foo","bar"]' 500  ! etc...
 `t` will convert the param list to JSON form for passing to the server.
 A numeric status code terminates processing of POST parameters.
+** As a special case, when one POST argument is a string ending in `.tar`,
+`t` will invoke `curl` with `--data-binary @PATH` and
+set `Content-type: application/x-tar`. This is useful for `build` endpoints.
+(To override `Content-type`, simply pass along an extra string argument
+matching `application/*`):
+      t POST myentrypoint /mytmpdir/myfile.tar application/foo 400
 
 * The final arguments are one or more expected string results. If an
 argument starts with a dot, `t` will invoke `jq` on the output to
diff --git a/test/apiv2/test-apiv2 b/test/apiv2/test-apiv2
index c644b9578..47934cca9 100755
--- a/test/apiv2/test-apiv2
+++ b/test/apiv2/test-apiv2
@@ -182,6 +182,7 @@ function t() {
     local method=$1; shift
     local path=$1; shift
     local curl_args
+    local content_type="application/json"
 
     local testname="$method $path"
     # POST requests may be followed by one or more key=value pairs.
@@ -190,13 +191,21 @@ function t() {
         local -a post_args
         for arg; do
             case "$arg" in
-                *=*)              post_args+=("$arg"); shift ;;
+                *=*)              post_args+=("$arg");
+                                  shift;;
+                *.tar)            curl_args="--data-binary @$arg" ;
+                                  content_type="application/x-tar";
+                                  shift;;
+                application/*)    content_type="$arg";
+                                  shift;;
                 [1-9][0-9][0-9])  break;;
                 *)                die "Internal error: invalid POST arg '$arg'" ;;
             esac
         done
-        curl_args="-d $(jsonify ${post_args[@]})"
-        testname="$testname [$curl_args]"
+        if [[ -z "$curl_args" ]]; then
+            curl_args="-d $(jsonify ${post_args[@]})"
+            testname="$testname [$curl_args]"
+        fi
     fi
 
     # entrypoint path can include a descriptive comment; strip it off
@@ -229,7 +238,7 @@ function t() {
     rm -f $WORKDIR/curl.*
     # -s = silent, but --write-out 'format' gives us important response data
     response=$(curl -s -X $method ${curl_args}                   \
-                    -H 'Content-type: application/json'          \
+                    -H "Content-type: $content_type"             \
                     --dump-header $WORKDIR/curl.headers.out       \
                     --write-out '%{http_code}^%{content_type}^%{time_total}' \
                     -o $WORKDIR/curl.result.out "$url")
@@ -328,10 +337,13 @@ function start_service() {
     fi
 
     echo $WORKDIR
-    $PODMAN_BIN --root $WORKDIR/server_root --syslog=true \
-                system service \
-                --time 15 \
-                tcp:127.0.0.1:$PORT \
+    # Some tests use shortnames; force registry override to work around
+    # docker.io throttling.
+    env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf $PODMAN_BIN \
+        --root $WORKDIR/server_root --syslog=true \
+        system service \
+        --time 15 \
+        tcp:127.0.0.1:$PORT \
         &> $WORKDIR/server.log &
     service_pid=$!
 
@@ -460,7 +472,8 @@ function wait_for_port() {
 ############
 function podman() {
     echo "\$ $PODMAN_BIN $*"                       >>$WORKDIR/output.log
-    $PODMAN_BIN --root $WORKDIR/server_root "$@"   >>$WORKDIR/output.log 2>&1
+    env CONTAINERS_REGISTRIES_CONF=$TESTS_DIR/../registries.conf \
+        $PODMAN_BIN --root $WORKDIR/server_root "$@"   >>$WORKDIR/output.log 2>&1
 }
 
 ####################
-- 
cgit v1.2.3-54-g00ecf