# -*- sh -*-
#
# test container-related endpoints
#

# WORKDIR=/data
ENV_WORKDIR_IMG=quay.io/libpod/testimage:20200929
MultiTagName=localhost/test/testformultitag:tag

podman pull $IMAGE &>/dev/null
podman tag $IMAGE $MultiTagName
podman pull $ENV_WORKDIR_IMG &>/dev/null
# Unimplemented
#t POST libpod/containers/create '' 201 'sdf'

# Ensure clean slate
podman rm -a -f &>/dev/null

t GET "libpod/containers/json (at start: clean slate)" 200 length=0

podman run $IMAGE true

t GET libpod/containers/json 200 length=0

t GET libpod/containers/json?all=true 200 \
  length=1 \
  .[0].Id~[0-9a-f]\\{64\\} \
  .[0].Image=$IMAGE \
  .[0].Command[0]="true" \
  .[0].State~\\\(exited\\\|stopped\\\) \
  .[0].ExitCode=0 \
  .[0].IsInfra=false

# Test compat API for Network Settings (.Network is N/A when rootless)
network_expect=
if root; then
    network_expect='.[0].NetworkSettings.Networks.podman.NetworkID=podman'
fi
t GET /containers/json?all=true 200 \
  length=1 \
  .[0].Id~[0-9a-f]\\{64\\} \
  .[0].Image=$IMAGE \
  $network_expect

# Make sure `limit` works.
t GET libpod/containers/json?limit=1 200 \
  length=1 \
  .[0].Id~[0-9a-f]\\{64\\} \
  .[0].Image=$IMAGE \
  .[0].Command[0]="true" \
  .[0].State~\\\(exited\\\|stopped\\\) \
  .[0].ExitCode=0 \
  .[0].IsInfra=false

# Make sure `last` works, which is an alias for `limit`.
# See https://github.com/containers/podman/issues/6413.
t GET libpod/containers/json?last=1 200 \
  length=1 \
  .[0].Id~[0-9a-f]\\{64\\} \
  .[0].Image=$IMAGE \
  .[0].Command[0]="true" \
  .[0].State~\\\(exited\\\|stopped\\\) \
  .[0].ExitCode=0 \
  .[0].IsInfra=false

cid=$(jq -r '.[0].Id' <<<"$output")

if root; then
    t GET libpod/containers/stats?containers='[$cid]' 200
else
    if have_cgroupsv2; then
        t GET libpod/containers/stats?containers='[$cid]' 200
    else
        t GET libpod/containers/stats?containers='[$cid]' 409
    fi
fi

t DELETE libpod/containers/$cid 204

# Issue #6799: it should be possible to start a container, even w/o args.
t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
# Prior to the fix in #6835, this would fail 500 "args must not be empty"
t POST   libpod/containers/${cid}/start 204
# Container should exit almost immediately. Wait for it, confirm successful run
t POST   "libpod/containers/${cid}/wait?condition=stopped&condition=exited"  200 '0'
t GET    libpod/containers/${cid}/json 200 \
  .Id=$cid \
  .State.Status~\\\(exited\\\|stopped\\\) \
  .State.Running=false \
  .State.ExitCode=0
t DELETE libpod/containers/$cid 204

CNAME=myfoo
podman run --name $CNAME $IMAGE -td top
t GET libpod/containers/json?all=true 200 \
  .[0].Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.[0].Id' <<<"$output")

# No such container
t POST "libpod/commit?container=nonesuch" 404

# Comment can only be used with docker format, not OCI
cparam="repo=newrepo&comment=foo&author=bob"
t POST "libpod/commit?container=$CNAME&$cparam"  500 \
  .cause="messages are only compatible with the docker image format (-f docker)"

# Commit a new image from the container
t POST "libpod/commit?container=$CNAME" 200 \
  .Id~[0-9a-f]\\{64\\}
iid=$(jq -r '.Id' <<<"$output")
t GET libpod/images/$iid/json 200 \
  .RepoTags[0]=null \
  .Author="" \
  .Comment=""

# Commit a new image w/o tag
cparam="repo=newrepo&comment=foo&author=bob&format=docker"
t POST "libpod/commit?container=$CNAME&$cparam" 200
t GET libpod/images/newrepo:latest/json 200 \
  .RepoTags[0]=localhost/newrepo:latest	\
  .Author=bob \
  .Comment=foo

# Commit a new image w/ specified tag and author
cparam="repo=newrepo&tag=v1&author=alice"
t POST "libpod/commit?container=$cid&$cparam&pause=false" 200
t GET libpod/images/newrepo:v1/json 200 \
  .RepoTags[0]=localhost/newrepo:v1     \
  .Author=alice

# Commit a new image w/ full parameters
cparam="repo=newrepo&tag=v2&comment=bar&author=eric"
cparam="$cparam&format=docker&changes=CMD=/bin/foo"
t POST "libpod/commit?container=${cid:0:12}&$cparam&pause=true" 200
t GET libpod/images/newrepo:v2/json 200 \
  .RepoTags[0]=localhost/newrepo:v2	\
  .Author=eric \
  .Comment=bar \
  .Config.Cmd[-1]="/bin/foo"

# Create a container for testing the container initializing later
podman create -t -i --name myctr $IMAGE ls

# Check configuration before initializing
t GET libpod/containers/myctr/json 200 \
  .Id~[0-9a-f]\\{64\\} \
  .State.Status="configured" \
  .State.Pid=0 \
  .ResolvConfPath="" \
  .HostnamePath="" \
  .HostsPath="" \
  .NetworkSettings.SandboxKey=""

cpid_file=$(jq -r '.ConmonPidFile' <<<"$output")
userdata_path=$(dirname $cpid_file)

# Initializing the container
t POST libpod/containers/myctr/init 204

# Check configuration after initializing
t GET libpod/containers/myctr/json 200 \
  .Id~[0-9a-f]\\{64\\} \
  .State.Status="created" \
  .State.Pid~[0-9]\\{1\,8\\} \
  .ResolvConfPath=$userdata_path/resolv.conf \
  .HostnamePath=$userdata_path/hostname \
  .HostsPath=$userdata_path/hosts \
  .NetworkSettings.SandboxKey~.*/netns/cni- \
  .OCIConfigPath~.*config\.json \
  .GraphDriver.Data.MergedDir~.*merged

# Test TS are in UTC
t GET containers/myctr/json 200 \
  .Created~.*Z \
  .State.StartedAt~.*Z \
  .State.FinishedAt~.*Z

t DELETE images/localhost/newrepo:latest?force=true 200
t DELETE images/localhost/newrepo:v1?force=true 200
t DELETE images/localhost/newrepo:v2?force=true 200
t DELETE libpod/containers/$cid 204
t DELETE libpod/containers/myctr 204
t DELETE libpod/containers/bogus 404


# test apiv2 create container with correct entrypoint and cmd
# --data '{"Image":"quay.io/libpod/alpine_labels:latest","Entrypoint":["echo"],"Cmd":["param1","param2"]}'
t POST containers/create \
  Image=$IMAGE \
  Entrypoint='["echo"]' \
  Cmd='["param1","param2"]' \
  201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .Config.Entrypoint[0]="echo" \
  .Config.Cmd[0]="param1" \
  .Config.Cmd[1]="param2" \
  .Path="echo" \
  .Args[0]="param1" \
  .Args[1]="param2"
t DELETE containers/$cid 204

# test only set the entrypoint, Cmd should be []
t POST containers/create \
  Image=$IMAGE \
  Entrypoint='["echo","param1"]' \
  201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .Config.Entrypoint[0]="echo" \
  .Config.Entrypoint[1]="param1" \
  .Config.Cmd='[]' \
  .Path="echo" \
  .Args[0]="param1"

# create a running container for after
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='[]' \
  .Path="top" \
  .NetworkSettings.Networks.podman.NetworkID=podman
t POST  containers/${cid_top}/start 204
# make sure the container is running
t GET containers/${cid_top}/json 200 \
  .State.Status="running"

# 0 means unlimited, need same with docker
t GET containers/json?limit=0 200 \
  .[0].Id~[0-9a-f]\\{64\\}

t GET 'containers/json?limit=0&all=1' 200 \
  .[0].Id~[0-9a-f]\\{64\\} \
  .[1].Id~[0-9a-f]\\{64\\}

t GET containers/json?limit=2 200 length=2

# Filter with two ids should return both container
t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"]}&all=1' 200 length=2
# Filter with two ids and status running should return only 1 container
t GET containers/json?filters='{"id":["'${cid}'","'${cid_top}'"],"status":["running"]}&all=1' 200 \
  length=1 \
  .[0].Id=${cid_top}

t POST containers/${cid_top}/stop 204

t DELETE containers/$cid 204
t DELETE containers/$cid_top 204

# test the WORKDIR and StopSignal
t POST containers/create \
  Image=$ENV_WORKDIR_IMG \
  WorkingDir=/dataDir \
  StopSignal=9 \
  201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .Config.WorkingDir="/dataDir" \
  .Config.StopSignal="9"

t DELETE containers/$cid 204

# when the image had multi tags, the container's Image should be correct
# Fixes https://github.com/containers/podman/issues/8547
t POST containers/create Image=${MultiTagName} 201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .Image=${MultiTagName}
t DELETE containers/$cid 204
t DELETE images/${MultiTagName} 200
# vim: filetype=sh

# Test Volumes field adds an anonymous volume
t POST containers/create Image=$IMAGE Volumes='{"/test":{}}' 201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .Mounts[0].Destination="/test"

t DELETE containers/$cid?v=true 204

# test port mapping
podman run -d --rm --name bar -p 8080:9090 $IMAGE top

t GET containers/json 200 \
  .[0].Ports[0].PrivatePort=9090 \
  .[0].Ports[0].PublicPort=8080 \
  .[0].Ports[0].Type="tcp"

podman stop bar

#compat api list containers sanity checks
t GET containers/json?filters='garb1age}' 500 \
    .cause="invalid character 'g' looking for beginning of value"
t GET containers/json?filters='{"label":["testl' 500 \
    .cause="unexpected end of JSON input"

#libpod api list containers sanity checks
t GET libpod/containers/json?filters='garb1age}' 500 \
    .cause="invalid character 'g' looking for beginning of value"
t GET libpod/containers/json?filters='{"label":["testl' 500 \
    .cause="unexpected end of JSON input"

# Prune containers - bad filter input
t POST containers/prune?filters='garb1age}' 500 \
    .cause="invalid character 'g' looking for beginning of value"
t POST libpod/containers/prune?filters='garb1age}' 500 \
    .cause="invalid character 'g' looking for beginning of value"

# Prune containers with illformed label
t POST containers/prune?filters='{"label":["tes' 500 \
    .cause="unexpected end of JSON input"
t POST libpod/containers/prune?filters='{"label":["tes' 500 \
    .cause="unexpected end of JSON input"

t GET libpod/containers/json?filters='{"label":["testlabel"]}' 200 length=0

# libpod api: do not use list filters for prune
t POST libpod/containers/prune?filters='{"name":["anyname"]}' 500 \
    .cause="name is an invalid filter"
t POST libpod/containers/prune?filters='{"id":["anyid"]}' 500 \
    .cause="id is an invalid filter"
t POST libpod/containers/prune?filters='{"network":["anynetwork"]}' 500 \
    .cause="network is an invalid filter"

# compat api: do not use list filters for prune
t POST containers/prune?filters='{"name":["anyname"]}' 500 \
    .cause="name is an invalid filter"
t POST containers/prune?filters='{"id":["anyid"]}' 500 \
    .cause="id is an invalid filter"
t POST containers/prune?filters='{"network":["anynetwork"]}' 500 \
    .cause="network is an invalid filter"

# Test CPU limit (NanoCPUs)
t POST containers/create Image=$IMAGE HostConfig='{"NanoCpus":500000}' 201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .HostConfig.NanoCpus=500000

t DELETE containers/$cid?v=true 204

# Test Compat Create with default network mode (#10569)
t POST containers/create Image=$IMAGE HostConfig='{"NetworkMode":"default"}' 201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .HostConfig.NetworkMode="bridge"

t DELETE containers/$cid?v=true 204

# Test Compat Create with healthcheck, check default values
t POST containers/create Image=$IMAGE Cmd='["top"]' Healthcheck='{"Test":["true"]}' 201 \
  .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
  .Config.Healthcheck.Interval=30000000000 \
  .Config.Healthcheck.Timeout=30000000000 \
  .Config.Healthcheck.Retries=3

# compat api: Test for mount options support
payload='{"Mounts":[{"Type":"tmpfs","Target":"/mnt/scratch","TmpfsOptions":{"SizeBytes":1024,"Mode":755}}]}'
t POST containers/create Image=$IMAGE HostConfig="$payload" 201 .Id~[0-9a-f]\\{64\\}
cid=$(jq -r '.Id' <<<"$output")
t GET containers/$cid/json 200 \
    .HostConfig.Tmpfs['"/mnt/scratch"']~.*size=1024.* \
    .HostConfig.Tmpfs['"/mnt/scratch"']~.*mode=755.*

t DELETE containers/$cid?v=true 204