system tests: prevent leading tabs

Replace existing tab indentations with spaces, and add
a test to CI to prevent new ones from sneaking in.

Signed-off-by: Ed Santiago <santiago@redhat.com>
This commit is contained in:
Ed Santiago
2023-02-15 13:16:34 -07:00
parent d63d91694e
commit 86e55d0ec1
13 changed files with 117 additions and 112 deletions

View File

@ -28,6 +28,11 @@ msg "Checking Cirrus YAML"
# shellcheck disable=SC2154 # shellcheck disable=SC2154
showrun $SCRIPT_BASE/cirrus_yaml_test.py showrun $SCRIPT_BASE/cirrus_yaml_test.py
msg "Checking for leading tabs in system tests"
if grep -n ^$'\t' test/system/*; then
die "Found leading tabs in system tests. Use spaces to indent, not tabs."
fi
# Defined by CI config. # Defined by CI config.
# shellcheck disable=SC2154 # shellcheck disable=SC2154
if [[ "${DISTRO_NV}" =~ fedora ]]; then if [[ "${DISTRO_NV}" =~ fedora ]]; then

View File

@ -14,41 +14,41 @@ function _tag_and_check() {
} }
@test "podman tag/untag" { @test "podman tag/untag" {
# Test a fully-qualified image reference. # Test a fully-qualified image reference.
_tag_and_check registry.com/image:latest registry.com/image:latest _tag_and_check registry.com/image:latest registry.com/image:latest
# Test a reference without tag and make sure ":latest" is appended. # Test a reference without tag and make sure ":latest" is appended.
_tag_and_check registry.com/image registry.com/image:latest _tag_and_check registry.com/image registry.com/image:latest
# Test a tagged short image and make sure "localhost/" is prepended. # Test a tagged short image and make sure "localhost/" is prepended.
_tag_and_check image:latest localhost/image:latest _tag_and_check image:latest localhost/image:latest
# Test a short image without tag and make sure "localhost/" is # Test a short image without tag and make sure "localhost/" is
# prepended and ":latest" is appended. # prepended and ":latest" is appended.
_tag_and_check image localhost/image:latest _tag_and_check image localhost/image:latest
# Test error case. # Test error case.
run_podman 125 untag $IMAGE registry.com/foo:bar run_podman 125 untag $IMAGE registry.com/foo:bar
is "$output" "Error: registry.com/foo:bar: tag not known" is "$output" "Error: registry.com/foo:bar: tag not known"
} }
@test "podman untag all" { @test "podman untag all" {
# First get the image ID # First get the image ID
run_podman inspect --format '{{.ID}}' $IMAGE run_podman inspect --format '{{.ID}}' $IMAGE
iid=$output iid=$output
# Add a couple of tags # Add a couple of tags
run_podman tag $IMAGE registry.com/1:latest registry.com/2:latest registry.com/3:latest run_podman tag $IMAGE registry.com/1:latest registry.com/2:latest registry.com/3:latest
# Untag with arguments to for all tags to be removed # Untag with arguments to for all tags to be removed
run_podman untag $iid run_podman untag $iid
# Now make sure all tags are removed # Now make sure all tags are removed
run_podman image inspect $iid --format "{{.RepoTags}}" run_podman image inspect $iid --format "{{.RepoTags}}"
is "$output" "\[\]" "untag by ID leaves empty set of tags" is "$output" "\[\]" "untag by ID leaves empty set of tags"
# Restore image # Restore image
run_podman tag $iid $IMAGE run_podman tag $iid $IMAGE
} }
# vim: filetype=sh # vim: filetype=sh

View File

@ -639,10 +639,10 @@ json-file | f
run_podman run --name=$randomname --rootfs $romount:O echo "Hello world" run_podman run --name=$randomname --rootfs $romount:O echo "Hello world"
is "$output" "Hello world" is "$output" "Hello world"
run_podman container inspect $randomname --format "{{.ImageDigest}}" run_podman container inspect $randomname --format "{{.ImageDigest}}"
is "$output" "" "Empty image digest for --rootfs container" is "$output" "" "Empty image digest for --rootfs container"
run_podman rm -f -t0 $randomname run_podman rm -f -t0 $randomname
run_podman image unmount $IMAGE run_podman image unmount $IMAGE
fi fi
} }

View File

@ -178,7 +178,7 @@ function __run_healthcheck_container() {
break break
fi fi
sleep 0.5 sleep 0.5
done done
run_podman rm -f $cname run_podman rm -f $cname

View File

@ -275,7 +275,7 @@ load helpers
run_podman exec $destcontainer cat "/$dest_fullname" run_podman exec $destcontainer cat "/$dest_fullname"
is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)" is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
# To CREATED container # To CREATED container
run_podman create $IMAGE sleep infinity run_podman create $IMAGE sleep infinity
destcontainer="$output" destcontainer="$output"
destcontainers+=($destcontainer) destcontainers+=($destcontainer)
@ -303,7 +303,7 @@ load helpers
run_podman cp cpcontainer:$src $destcontainer:"/$dest" run_podman cp cpcontainer:$src $destcontainer:"/$dest"
run_podman exec $destcontainer cat "/$dest_fullname" run_podman exec $destcontainer cat "/$dest_fullname"
is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)" is "$output" "${randomcontent[$id]}" "$description (cp ctr:$src to /$dest)"
# To CREATED container # To CREATED container
run_podman create $IMAGE sleep infinity run_podman create $IMAGE sleep infinity
destcontainer="$output" destcontainer="$output"
destcontainers+=($destcontainer) destcontainers+=($destcontainer)
@ -518,7 +518,7 @@ load helpers
is "$output" "${randomcontent[0]} is "$output" "${randomcontent[0]}
${randomcontent[1]}" "$description" ${randomcontent[1]}" "$description"
# To CREATED container # To CREATED container
run_podman create $IMAGE sleep infinity run_podman create $IMAGE sleep infinity
destcontainer="$output" destcontainer="$output"
destcontainers+=($destcontainer) destcontainers+=($destcontainer)
@ -545,7 +545,7 @@ ${randomcontent[1]}" "$description"
unset dest_fullname unset dest_fullname
fi fi
# To RUNNING container # To RUNNING container
run_podman run -d $IMAGE sleep infinity run_podman run -d $IMAGE sleep infinity
destcontainer="$output" destcontainer="$output"
destcontainers+=($destcontainer) destcontainers+=($destcontainer)
@ -554,7 +554,7 @@ ${randomcontent[1]}" "$description"
is "$output" "${randomcontent[0]} is "$output" "${randomcontent[0]}
${randomcontent[1]}" "$description" ${randomcontent[1]}" "$description"
# To CREATED container # To CREATED container
run_podman create $IMAGE sleep infinity run_podman create $IMAGE sleep infinity
destcontainer="$output" destcontainer="$output"
destcontainers+=($destcontainer) destcontainers+=($destcontainer)

View File

@ -397,7 +397,7 @@ EOF
if is_remote; then if is_remote; then
ENVHOST="" ENVHOST=""
else else
ENVHOST="--env-host" ENVHOST="--env-host"
fi fi
# Run without args - should run the above script. Verify its output. # Run without args - should run the above script. Verify its output.
@ -584,7 +584,7 @@ EOF
# Build an image. For .dockerignore # Build an image. For .dockerignore
local -a ignoreflag local -a ignoreflag
unset ignoreflag unset ignoreflag
if [[ $ignorefile != ".dockerignore" ]]; then if [[ $ignorefile != ".dockerignore" ]]; then
ignoreflag="--ignorefile $tmpdir/$ignorefile" ignoreflag="--ignorefile $tmpdir/$ignorefile"
fi fi
@ -1029,14 +1029,14 @@ EOF
touch $tmpdir/empty-file.txt touch $tmpdir/empty-file.txt
if is_remote && ! is_rootless ; then if is_remote && ! is_rootless ; then
# TODO: set this file's owner to a UID:GID that will not be mapped # TODO: set this file's owner to a UID:GID that will not be mapped
# in the context where the remote server is running, which generally # in the context where the remote server is running, which generally
# requires us to be root (or running with more mapped IDs) on the # requires us to be root (or running with more mapped IDs) on the
# client, but not root (or running with fewer mapped IDs) on the # client, but not root (or running with fewer mapped IDs) on the
# remote server # remote server
# 4294967292:4294967292 (0xfffffffc:0xfffffffc) isn't that, but # 4294967292:4294967292 (0xfffffffc:0xfffffffc) isn't that, but
# it will catch errors where a remote server doesn't apply the right # it will catch errors where a remote server doesn't apply the right
# default as it copies content into the container # default as it copies content into the container
chown 4294967292:4294967292 $tmpdir/empty-file.txt chown 4294967292:4294967292 $tmpdir/empty-file.txt
fi fi
cat >$tmpdir/Dockerfile <<EOF cat >$tmpdir/Dockerfile <<EOF

View File

@ -448,13 +448,13 @@ NeedsChown | true
# and does not work remotely # and does not work remotely
run_podman volume mount ${myvolume} run_podman volume mount ${myvolume}
mnt=${output} mnt=${output}
echo $mytext >$mnt/$myfile echo $mytext >$mnt/$myfile
run_podman run -v ${myvolume}:/vol:z $IMAGE cat /vol/$myfile run_podman run -v ${myvolume}:/vol:z $IMAGE cat /vol/$myfile
is "$output" "$mytext" "$myfile should exist within the containers volume and contain $mytext" is "$output" "$mytext" "$myfile should exist within the containers volume and contain $mytext"
run_podman volume unmount ${myvolume} run_podman volume unmount ${myvolume}
else else
run_podman 125 volume mount ${myvolume} run_podman 125 volume mount ${myvolume}
is "$output" "Error: cannot run command \"podman volume mount\" in rootless mode, must execute.*podman unshare.*first" "Should fail and complain about unshare" is "$output" "Error: cannot run command \"podman volume mount\" in rootless mode, must execute.*podman unshare.*first" "Should fail and complain about unshare"
fi fi
} }

View File

@ -113,12 +113,12 @@ Log[-1].Output | \"Uh-oh on stdout!\\\nUh-oh on stderr!\"
img="healthcheck_i" img="healthcheck_i"
for policy in none kill restart stop;do for policy in none kill restart stop;do
if [[ $policy == "none" ]];then if [[ $policy == "none" ]];then
# Do not remove the /uh-oh file for `none` as we want to # Do not remove the /uh-oh file for `none` as we want to
# demonstrate that no action was taken # demonstrate that no action was taken
_build_health_check_image $img _build_health_check_image $img
else else
_build_health_check_image $img cleanfile _build_health_check_image $img cleanfile
fi fi
# Run that healthcheck image. # Run that healthcheck image.
@ -140,19 +140,19 @@ Log[-1].Output | \"Uh-oh on stdout!\\\nUh-oh on stderr!\"
is "$output" "unhealthy" "output from 'podman healthcheck run' (policy: $policy)" is "$output" "unhealthy" "output from 'podman healthcheck run' (policy: $policy)"
run_podman inspect $ctr --format "{{.State.Status}} {{.Config.HealthcheckOnFailureAction}}" run_podman inspect $ctr --format "{{.State.Status}} {{.Config.HealthcheckOnFailureAction}}"
if [[ $policy == "restart" ]];then if [[ $policy == "restart" ]];then
# Container has been restarted and health check works again # Container has been restarted and health check works again
is "$output" "running $policy" "container has been restarted" is "$output" "running $policy" "container has been restarted"
run_podman container inspect $ctr --format "{{.State.Healthcheck.FailingStreak}}" run_podman container inspect $ctr --format "{{.State.Healthcheck.FailingStreak}}"
is "$output" "0" "Failing streak of restarted container should be 0 again" is "$output" "0" "Failing streak of restarted container should be 0 again"
run_podman healthcheck run $ctr run_podman healthcheck run $ctr
elif [[ $policy == "none" ]];then elif [[ $policy == "none" ]];then
# Container is still running and health check still broken # Container is still running and health check still broken
is "$output" "running $policy" "container continued running" is "$output" "running $policy" "container continued running"
run_podman 1 healthcheck run $ctr run_podman 1 healthcheck run $ctr
is "$output" "unhealthy" "output from 'podman healthcheck run' (policy: $policy)" is "$output" "unhealthy" "output from 'podman healthcheck run' (policy: $policy)"
else else
# kill and stop yield the container into a non-running state # kill and stop yield the container into a non-running state
is "$output" ".* $policy" "container was stopped/killed (policy: $policy)" is "$output" ".* $policy" "container was stopped/killed (policy: $policy)"
assert "$output" != "running $policy" assert "$output" != "running $policy"
# also make sure that it's not stuck in the stopping state # also make sure that it's not stuck in the stopping state

View File

@ -189,10 +189,10 @@ function check_listen_env() {
local stdenv="$1" local stdenv="$1"
local context="$2" local context="$2"
if is_remote; then if is_remote; then
is "$output" "$stdenv" "LISTEN Environment did not pass: $context" is "$output" "$stdenv" "LISTEN Environment did not pass: $context"
else else
out=$(for o in $output; do echo $o; done| sort) out=$(for o in $output; do echo $o; done| sort)
std=$(echo "$stdenv std=$(echo "$stdenv
LISTEN_PID=1 LISTEN_PID=1
LISTEN_FDS=1 LISTEN_FDS=1
LISTEN_FDNAMES=listen_fdnames" | sort) LISTEN_FDNAMES=listen_fdnames" | sort)

View File

@ -27,9 +27,9 @@ function check_label() {
is "$type" "$1" "SELinux type" is "$type" "$1" "SELinux type"
if [ -n "$2" ]; then if [ -n "$2" ]; then
# e.g. from the above example -> "s0:c45,c745" # e.g. from the above example -> "s0:c45,c745"
range=$(cut -d: -f4,5 <<<"$context") range=$(cut -d: -f4,5 <<<"$context")
is "$range" "$2^@" "SELinux range" is "$range" "$2^@" "SELinux range"
fi fi
} }
@ -66,9 +66,9 @@ function check_label() {
# FIXME this test fails when run rootless with runc: # FIXME this test fails when run rootless with runc:
# Error: container_linux.go:367: starting container process caused: process_linux.go:495: container init caused: readonly path /proc/asound: operation not permitted: OCI permission denied # Error: container_linux.go:367: starting container process caused: process_linux.go:495: container init caused: readonly path /proc/asound: operation not permitted: OCI permission denied
if is_rootless; then if is_rootless; then
runtime=$(podman_runtime) runtime=$(podman_runtime)
test "$runtime" == "crun" \ test "$runtime" == "crun" \
|| skip "runtime is $runtime; this test requires crun" || skip "runtime is $runtime; this test requires crun"
fi fi
check_label "--pid=host" "spc_t" check_label "--pid=host" "spc_t"
@ -96,10 +96,10 @@ function check_label() {
skip_if_no_selinux skip_if_no_selinux
run_podman run -d --name myc \ run_podman run -d --name myc \
--security-opt seccomp=unconfined \ --security-opt seccomp=unconfined \
--security-opt label=type:spc_t \ --security-opt label=type:spc_t \
--security-opt label=level:s0 \ --security-opt label=level:s0 \
$IMAGE sh -c 'while test ! -e /stop; do sleep 0.1; done' $IMAGE sh -c 'while test ! -e /stop; do sleep 0.1; done'
run_podman inspect --format='{{ .HostConfig.SecurityOpt }}' myc run_podman inspect --format='{{ .HostConfig.SecurityOpt }}' myc
is "$output" "[label=type:spc_t,label=level:s0 seccomp=unconfined]" \ is "$output" "[label=type:spc_t,label=level:s0 seccomp=unconfined]" \
"'podman inspect' preserves all --security-opts" "'podman inspect' preserves all --security-opts"
@ -118,7 +118,7 @@ function check_label() {
skip_if_rootless_cgroupsv1 skip_if_rootless_cgroupsv1
if [[ $(podman_runtime) == "runc" ]]; then if [[ $(podman_runtime) == "runc" ]]; then
skip "some sort of runc bug, not worth fixing (#11784)" skip "some sort of runc bug, not worth fixing (#11784)"
fi fi
run_podman run -d --name myctr $IMAGE top run_podman run -d --name myctr $IMAGE top
@ -136,7 +136,7 @@ function check_label() {
# net NS: do not share context # net NS: do not share context
run_podman run --rm --net container:myctr $IMAGE cat -v /proc/self/attr/current run_podman run --rm --net container:myctr $IMAGE cat -v /proc/self/attr/current
assert "$output" != "$context_c1" \ assert "$output" != "$context_c1" \
"run --net : context should != context of running container" "run --net : context should != context of running container"
# The 'myctr2' above was not run with --rm, so it still exists, and # The 'myctr2' above was not run with --rm, so it still exists, and
# we can't remove the original container until this one is gone. # we can't remove the original container until this one is gone.
@ -157,8 +157,8 @@ function check_label() {
# We don't need a fullblown pause container; avoid pulling the k8s one # We don't need a fullblown pause container; avoid pulling the k8s one
run_podman pod create --name myselinuxpod \ run_podman pod create --name myselinuxpod \
--infra-image $IMAGE \ --infra-image $IMAGE \
--infra-command /home/podman/pause --infra-command /home/podman/pause
# Get baseline # Get baseline
run_podman run --rm --pod myselinuxpod $IMAGE cat -v /proc/self/attr/current run_podman run --rm --pod myselinuxpod $IMAGE cat -v /proc/self/attr/current
@ -189,7 +189,7 @@ function check_label() {
# Even after #7902, labels (':c123,c456') should be different # Even after #7902, labels (':c123,c456') should be different
run_podman run --rm --pod myselinuxpod $IMAGE cat -v /proc/self/attr/current run_podman run --rm --pod myselinuxpod $IMAGE cat -v /proc/self/attr/current
assert "$output" != "$context_c1" \ assert "$output" != "$context_c1" \
"context of two separate containers should be different" "context of two separate containers should be different"
run_podman pod rm myselinuxpod run_podman pod rm myselinuxpod
} }
@ -201,16 +201,16 @@ function check_label() {
# runc and crun emit different diagnostics # runc and crun emit different diagnostics
runtime=$(podman_runtime) runtime=$(podman_runtime)
case "$runtime" in case "$runtime" in
# crun 0.20.1 changes the error message # crun 0.20.1 changes the error message
# from /proc/thread-self/attr/exec`: .* unable to assign # from /proc/thread-self/attr/exec`: .* unable to assign
# to /proc/self/attr/keycreate`: .* unable to process # to /proc/self/attr/keycreate`: .* unable to process
crun) expect="\`/proc/.*\`: OCI runtime error: unable to \(assign\|process\) security attribute" ;; crun) expect="\`/proc/.*\`: OCI runtime error: unable to \(assign\|process\) security attribute" ;;
# runc 1.1 changed the error message because of new selinux pkg that uses standard os.PathError, see # runc 1.1 changed the error message because of new selinux pkg that uses standard os.PathError, see
# https://github.com/opencontainers/selinux/pull/148/commits/a5dc47f74c56922d58ead05d1fdcc5f7f52d5f4e # https://github.com/opencontainers/selinux/pull/148/commits/a5dc47f74c56922d58ead05d1fdcc5f7f52d5f4e
# from failed to set /proc/self/attr/keycreate on procfs # from failed to set /proc/self/attr/keycreate on procfs
# to write /proc/self/attr/keycreate: invalid argument # to write /proc/self/attr/keycreate: invalid argument
runc) expect=".*: \(failed to set\|write\) /proc/self/attr/keycreate.*" ;; runc) expect=".*: \(failed to set\|write\) /proc/self/attr/keycreate.*" ;;
*) skip "Unknown runtime '$runtime'";; *) skip "Unknown runtime '$runtime'";;
esac esac
# The '.*' in the error below is for dealing with podman-remote, which # The '.*' in the error below is for dealing with podman-remote, which
@ -249,28 +249,28 @@ function check_label() {
# podman-remote has no 'unshare' # podman-remote has no 'unshare'
if is_rootless && ! is_remote; then if is_rootless && ! is_remote; then
run_podman unshare touch $tmpdir/test1 run_podman unshare touch $tmpdir/test1
# Relabel entire directory # Relabel entire directory
run_podman unshare chcon system_u:object_r:usr_t:s0 $tmpdir run_podman unshare chcon system_u:object_r:usr_t:s0 $tmpdir
run_podman start --attach label run_podman start --attach label
newlevel=$(secon -l $output) newlevel=$(secon -l $output)
is "$level" "$newlevel" "start should relabel with same SELinux labels" is "$level" "$newlevel" "start should relabel with same SELinux labels"
run ls -dZ $tmpdir run ls -dZ $tmpdir
is "$output" "system_u:object_r:container_file_t:$level $tmpdir" \ is "$output" "system_u:object_r:container_file_t:$level $tmpdir" \
"Confined Relabel Correctly" "Confined Relabel Correctly"
run ls -dZ $tmpdir/test1 run ls -dZ $tmpdir/test1
is "$output" "system_u:object_r:container_file_t:$level $tmpdir/test1" \ is "$output" "system_u:object_r:container_file_t:$level $tmpdir/test1" \
"Start did not Relabel" "Start did not Relabel"
# Relabel only file in subdir # Relabel only file in subdir
run_podman unshare chcon system_u:object_r:usr_t:s0 $tmpdir/test1 run_podman unshare chcon system_u:object_r:usr_t:s0 $tmpdir/test1
run_podman start --attach label run_podman start --attach label
newlevel=$(secon -l $output) newlevel=$(secon -l $output)
is "$level" "$newlevel" "start should use same SELinux labels" is "$level" "$newlevel" "start should use same SELinux labels"
run ls -dZ $tmpdir/test1 run ls -dZ $tmpdir/test1
is "$output" "system_u:object_r:usr_t:s0 $tmpdir/test1" \ is "$output" "system_u:object_r:usr_t:s0 $tmpdir/test1" \
"Start did not Relabel" "Start did not Relabel"
fi fi
run_podman run -v $tmpdir:/test:z $IMAGE cat /proc/self/attr/current run_podman run -v $tmpdir:/test:z $IMAGE cat /proc/self/attr/current
run ls -dZ $tmpdir run ls -dZ $tmpdir

View File

@ -226,7 +226,7 @@ load helpers.network
"sdfsdf" "sdfsdf"
run_podman run -d --network $mynetname -p 127.0.0.1:$myport:$myport \ run_podman run -d --network $mynetname -p 127.0.0.1:$myport:$myport \
$IMAGE nc -l -n -v -p $myport $IMAGE nc -l -n -v -p $myport
cid="$output" cid="$output"
# FIXME: debugging for #11871 # FIXME: debugging for #11871
@ -663,9 +663,9 @@ EOF
is "$output" "search example.com.*" "correct search domain" is "$output" "search example.com.*" "correct search domain"
local store=$output local store=$output
if is_netavark; then if is_netavark; then
is "$store" ".*nameserver $subnet.1.*" "integrated dns nameserver is set" is "$store" ".*nameserver $subnet.1.*" "integrated dns nameserver is set"
else else
is "$store" ".*nameserver 1.1.1.1${nl}nameserver $searchIP${nl}nameserver 1.0.0.1${nl}nameserver 8.8.8.8" "nameserver order is correct" is "$store" ".*nameserver 1.1.1.1${nl}nameserver $searchIP${nl}nameserver 1.0.0.1${nl}nameserver 8.8.8.8" "nameserver order is correct"
fi fi
# we should use the integrated dns server # we should use the integrated dns server
run_podman run --network $netname --rm $IMAGE cat /etc/resolv.conf run_podman run --network $netname --rm $IMAGE cat /etc/resolv.conf

View File

@ -567,7 +567,7 @@ EOF
run_podman kube play $YAML run_podman kube play $YAML
if selinux_enabled; then if selinux_enabled; then
run_podman inspect pod1-test1 --format "{{ .MountLabel }}" run_podman inspect pod1-test1 --format "{{ .MountLabel }}"
is "$output" "system_u:object_r:usr_t:s0:c1,c2" "Generated container should use filetype usr_t" is "$output" "system_u:object_r:usr_t:s0:c1,c2" "Generated container should use filetype usr_t"
fi fi
run_podman kube down $YAML run_podman kube down $YAML
} }

View File

@ -62,7 +62,7 @@ EOF
# container" errors from podman wait. # container" errors from podman wait.
CONTAINERS_CONF="$conf_tmp" run_podman '?' wait "$cid" CONTAINERS_CONF="$conf_tmp" run_podman '?' wait "$cid"
if [[ $status != 0 ]]; then if [[ $status != 0 ]]; then
is "$output" "Error:.*no such container" "unexpected error from podman wait" is "$output" "Error:.*no such container" "unexpected error from podman wait"
fi fi
# The --rm option means the container should no longer exist. # The --rm option means the container should no longer exist.