summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 16:20:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 16:20:50 +0000
commit318b0d0e7515e0a97e647906387ecf89455f3878 (patch)
tree905dcee34012fd33308dbfda2f7114343dd36e8b /tests
parentInitial commit. (diff)
downloadgolang-github-containers-storage-318b0d0e7515e0a97e647906387ecf89455f3878.tar.xz
golang-github-containers-storage-318b0d0e7515e0a97e647906387ecf89455f3878.zip
Adding upstream version 1.51.0+ds1.upstream/1.51.0+ds1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/abs.bats11
-rw-r--r--tests/apply-diff.bats103
-rw-r--r--tests/apply-junk.bats47
-rw-r--r--tests/bigdata.bats212
-rw-r--r--tests/changes.bats30
-rw-r--r--tests/check.bats1064
-rw-r--r--tests/cleanup-layer.bats17
-rw-r--r--tests/container-dirs.bats48
-rw-r--r--tests/container.bats36
-rw-r--r--tests/create-container.bats109
-rw-r--r--tests/create-image.bats54
-rw-r--r--tests/create-layer.bats93
-rw-r--r--tests/delete-container.bats80
-rw-r--r--tests/delete-image.bats27
-rw-r--r--tests/delete-layer.bats121
-rw-r--r--tests/delete.bats47
-rw-r--r--tests/diff.bats38
-rw-r--r--tests/diffsize.bats22
-rwxr-xr-xtests/helpers.bash332
-rw-r--r--tests/idmaps.bats1050
-rw-r--r--tests/image-by-digest.bats113
-rw-r--r--tests/image.bats56
-rw-r--r--tests/import-layer.bats136
-rw-r--r--tests/layers.bats58
-rw-r--r--tests/manifests.bats67
-rw-r--r--tests/metadata.bats137
-rw-r--r--tests/mount-layer.bats85
-rw-r--r--tests/names.bats722
-rw-r--r--tests/overlay-recreate.bats33
-rw-r--r--tests/split-store.bats109
-rw-r--r--tests/status.bats18
-rw-r--r--tests/stores.bats153
-rwxr-xr-xtests/test_drivers.bash56
-rwxr-xr-xtests/test_runner.bash18
-rw-r--r--tests/tools/Makefile34
-rw-r--r--tests/tools/go.mod16
-rw-r--r--tests/tools/go.sum22
-rw-r--r--tests/tools/tools.go12
38 files changed, 5386 insertions, 0 deletions
diff --git a/tests/abs.bats b/tests/abs.bats
new file mode 100644
index 0000000..1cccf28
--- /dev/null
+++ b/tests/abs.bats
@@ -0,0 +1,11 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "absolute-paths" {
+ cd ${TESTDIR}
+ storage --graph tmp1a/deep/root --run tmp1b/deep/runroot layers
+ storage --graph ./tmp2a/deep/root --run ./tmp2b/deep/runroot layers
+ storage --graph tmp1a/deep/root --run tmp1b/deep/runroot shutdown
+ storage --graph ./tmp2a/deep/root --run ./tmp2b/deep/runroot shutdown
+}
diff --git a/tests/apply-diff.bats b/tests/apply-diff.bats
new file mode 100644
index 0000000..83807c8
--- /dev/null
+++ b/tests/apply-diff.bats
@@ -0,0 +1,103 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "applydiff" {
+ # The checkdiffs function needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ # Create and populate three interesting layers.
+ populate
+
+ # Extract the layers.
+ storage diff -u -f $TESTDIR/lower.tar $lowerlayer
+ storage diff -c -f $TESTDIR/middle.tar $midlayer
+ storage diff -u -f $TESTDIR/upper.tar $upperlayer
+
+ # Delete the layers.
+ storage delete-layer $upperlayer
+ storage delete-layer $midlayer
+ storage delete-layer $lowerlayer
+
+ # Create new layers and populate them using the layer diffs.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ storage applydiff -f $TESTDIR/lower.tar "$lowerlayer"
+
+ run storage --debug=false create-layer "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midlayer="$output"
+ storage applydiff -f $TESTDIR/middle.tar "$midlayer"
+
+ run storage --debug=false create-layer "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ storage applydiff -f $TESTDIR/upper.tar "$upperlayer"
+
+ # The contents of these new layers should match what the old ones had.
+ checkchanges
+ checkdiffs
+}
+
+@test "apply-diff-from-staging-directory" {
+ case "$STORAGE_DRIVER" in
+ overlay*)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support diff-from-staging-directory"
+ ;;
+ esac
+
+ SRC=$TESTDIR/source
+ mkdir -p $SRC
+ createrandom $SRC/file1
+ createrandom $SRC/file2
+ createrandom $SRC/file3
+
+ local sconf=$TESTDIR/storage.conf
+
+ local root=`storage status 2>&1 | awk '/^Root:/{print $2}'`
+ local runroot=`storage status 2>&1 | awk '/^Run Root:/{print $3}'`
+
+ cat >$sconf <<EOF
+[storage]
+driver="overlay"
+graphroot="$root"
+runroot="$runroot"
+
+[storage.options]
+pull_options = {enable_partial_images = "true" }
+EOF
+
+ # Create a layer.
+ CONTAINERS_STORAGE_CONF=$sconf run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer="$output"
+
+ CONTAINERS_STORAGE_CONF=$sconf run storage --debug=false applydiff-using-staging-dir $layer $SRC
+ [ "$status" -eq 0 ]
+
+ name=safe-image
+ CONTAINERS_STORAGE_CONF=$sconf run storage --debug=false create-image --name $name $layer
+ [ "$status" -eq 0 ]
+
+ ctrname=foo
+ CONTAINERS_STORAGE_CONF=$sconf run storage --debug=false create-container --name $ctrname $name
+ [ "$status" -eq 0 ]
+
+ CONTAINERS_STORAGE_CONF=$sconf run storage --debug=false mount $ctrname
+ [ "$status" -eq 0 ]
+ mount="$output"
+
+ for i in file1 file2 file3 ; do
+ run cmp $SRC/$i $mount/$i
+ [ "$status" -eq 0 ]
+ done
+}
diff --git a/tests/apply-junk.bats b/tests/apply-junk.bats
new file mode 100644
index 0000000..164fa58
--- /dev/null
+++ b/tests/apply-junk.bats
@@ -0,0 +1,47 @@
+#!/usr/bin/env bats
+
+load helpers
+
+function applyjunk_main() {
+ # Create and try to populate layers with... garbage. It should be
+ # rejected cleanly.
+ compressed="$1"
+
+ storage create-layer --id layer-${compressed}
+
+ echo [[${compressed} /etc/os-release]]
+ if ! ${compressed} < /etc/os-release > junkfile ; then
+ skip "error running ${compressed}"
+ fi
+ run storage apply-diff --file junkfile layer-${compressed}
+ echo "$output"
+ [[ "$status" -ne 0 ]]
+ [[ "$output" =~ "invalid tar header" ]] || [[ "$output" =~ "unexpected EOF" ]]
+
+ echo [[${compressed}]]
+ echo "sorry, not even enough info for a tar header here" | ${compressed} > junkfile
+ run storage apply-diff --file junkfile layer-${compressed}
+ echo "$output"
+ [[ "$status" -ne 0 ]]
+ [[ "$output" =~ "unexpected EOF" ]]
+}
+
+@test "applyjunk-uncompressed" {
+ applyjunk_main cat
+}
+
+@test "applyjunk-gzip" {
+ applyjunk_main gzip
+}
+
+@test "applyjunk-bzip2" {
+ applyjunk_main bzip2
+}
+
+@test "applyjunk-xz" {
+ applyjunk_main xz
+}
+
+@test "applyjunk-zstd" {
+ applyjunk_main zstd
+}
diff --git a/tests/bigdata.bats b/tests/bigdata.bats
new file mode 100644
index 0000000..8d04415
--- /dev/null
+++ b/tests/bigdata.bats
@@ -0,0 +1,212 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "image-data" {
+ # Bail if "sha256sum" isn't available.
+ if test -z "$(which sha256sum 2> /dev/null)" ; then
+ skip "need sha256sum"
+ fi
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Make sure the image can be located.
+ storage exists -i $image
+
+ # Make sure the image has no big data items associated with it.
+ run storage --debug=false list-image-data $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "" ]
+
+ # Create two random files.
+ createrandom $TESTDIR/big-item-1 1234
+ createrandom $TESTDIR/big-item-2 5678
+
+ # Set each of those files as a big data item named after the file.
+ storage set-image-data -f $TESTDIR/big-item-1 $image big-item-1
+ storage set-image-data -f $TESTDIR/big-item-2 $image big-item-2
+
+ # Get a list of the items. Make sure they're both listed.
+ run storagewithsorting --debug=false list-image-data $image
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 2 ]
+ [ "${lines[0]}" = "big-item-1" ]
+ [ "${lines[1]}" = "big-item-2" ]
+
+ # Check that the recorded sizes of the items match what we decided above.
+ run storage get-image-data-size $image no-such-item
+ [ "$status" -ne 0 ]
+ run storage --debug=false get-image-data-size $image big-item-1
+ [ "$status" -eq 0 ]
+ [ "$output" -eq 1234 ]
+ run storage --debug=false get-image-data-size $image big-item-2
+ [ "$status" -eq 0 ]
+ [ "$output" -eq 5678 ]
+
+ # Check that we can distinguish between no-such-image and no-such-item.
+ run storage --debug=false get-image-data nosuchimage big-item
+ [ "$status" -ne 0 ]
+ echo "$output"
+ [[ "$output" =~ "image not known" ]]
+ run storage --debug=false get-image-data $image no-such-big-item
+ [ "$status" -ne 0 ]
+ echo "$output"
+ [[ "$output" =~ "does not exist" ]]
+
+ # Save the contents of the big data items to disk and compare them with the originals.
+ run storage --debug=false get-image-data $image no-such-item
+ [ "$status" -ne 0 ]
+ storage get-image-data -f $TESTDIR/big-item-1.2 $image big-item-1
+ cmp $TESTDIR/big-item-1 $TESTDIR/big-item-1.2
+ storage get-image-data -f $TESTDIR/big-item-2.2 $image big-item-2
+ cmp $TESTDIR/big-item-2 $TESTDIR/big-item-2.2
+
+ # Read the recorded digests of the items and compare them with the digests of the originals.
+ run storage get-image-data-digest $image no-such-item
+ [ "$status" -ne 0 ]
+ run storage --debug=false get-image-data-digest $image big-item-1
+ [ "$status" -eq 0 ]
+ sum=$(sha256sum $TESTDIR/big-item-1)
+ sum=sha256:"${sum%% *}"
+ echo output:"$output":
+ echo sum:"$sum":
+ [ "$output" = "$sum" ]
+ run storage --debug=false get-image-data-digest $image big-item-2
+ [ "$status" -eq 0 ]
+ sum=$(sha256sum $TESTDIR/big-item-2)
+ sum=sha256:"${sum%% *}"
+ echo output:"$output":
+ echo sum:"$sum":
+ [ "$output" = "$sum" ]
+}
+
+@test "container-data" {
+ # Bail if "sha256sum" isn't available.
+ if test -z "$(which sha256sum 2> /dev/null)" ; then
+ skip "need sha256sum"
+ fi
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container based on that image.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Make sure the container can be located.
+ storage exists -c $container
+
+ # Make sure the container has no big data items associated with it.
+ run storage --debug=false list-container-data $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "" ]
+
+ # Create two random files.
+ createrandom $TESTDIR/big-item-1 1234
+ createrandom $TESTDIR/big-item-2 5678
+
+ # Set each of those files as a big data item named after the file.
+ storage set-container-data -f $TESTDIR/big-item-1 $container big-item-1
+ storage set-container-data -f $TESTDIR/big-item-2 $container big-item-2
+
+ # Get a list of the items. Make sure they're both listed.
+ run storage --debug=false list-container-data $container
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 2 ]
+ [ "${lines[0]}" = "big-item-1" ]
+ [ "${lines[1]}" = "big-item-2" ]
+
+ # Check that the recorded sizes of the items match what we decided above.
+ run storage get-container-data-size $container no-such-item
+ [ "$status" -ne 0 ]
+ run storage --debug=false get-container-data-size $container big-item-1
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" -eq 1234 ]
+ run storage --debug=false get-container-data-size $container big-item-2
+ [ "$status" -eq 0 ]
+ [ "$output" -eq 5678 ]
+
+ # Save the contents of the big data items to disk and compare them with the originals.
+ run storage --debug=false get-container-data $container no-such-item
+ [ "$status" -ne 0 ]
+ storage get-container-data -f $TESTDIR/big-item-1.2 $container big-item-1
+ cmp $TESTDIR/big-item-1 $TESTDIR/big-item-1.2
+ storage get-container-data -f $TESTDIR/big-item-2.2 $container big-item-2
+ cmp $TESTDIR/big-item-2 $TESTDIR/big-item-2.2
+
+ # Read the recorded digests of the items and compare them with the digests of the originals.
+ run storage get-container-data-digest $container no-such-item
+ [ "$status" -ne 0 ]
+ run storage --debug=false get-container-data-digest $container big-item-1
+ [ "$status" -eq 0 ]
+ sum=$(sha256sum $TESTDIR/big-item-1)
+ sum=sha256:"${sum%% *}"
+ echo output:"$output":
+ echo sum:"$sum":
+ [ "$output" = "$sum" ]
+ run storage --debug=false get-container-data-digest $container big-item-2
+ [ "$status" -eq 0 ]
+ sum=$(sha256sum $TESTDIR/big-item-2)
+ sum=sha256:"${sum%% *}"
+ echo output:"$output":
+ echo sum:"$sum":
+ [ "$output" = "$sum" ]
+}
+
+@test "layer-data" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Make sure the layer has no big data items associated with it.
+ run storage --debug=false list-layer-data $layer
+ [ "$status" -eq 0 ]
+ [ "$output" = "" ]
+
+ # Create two random files.
+ createrandom $TESTDIR/big-item-1 1234
+ createrandom $TESTDIR/big-item-2 5678
+
+ # Set each of those files as a big data item named after the file.
+ storage set-layer-data -f $TESTDIR/big-item-1 $layer big-item-1
+ storage set-layer-data -f $TESTDIR/big-item-2 $layer big-item-2
+
+ # Get a list of the items. Make sure they're both listed.
+ run storage --debug=false list-layer-data $layer
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 2 ]
+ [ "${lines[0]}" = "big-item-1" ]
+ [ "${lines[1]}" = "big-item-2" ]
+
+ # Save the contents of the big data items to disk and compare them with the originals.
+ run storage --debug=false get-layer-data $layer no-such-item
+ [ "$status" -ne 0 ]
+ storage get-layer-data -f $TESTDIR/big-item-1.2 $layer big-item-1
+ cmp $TESTDIR/big-item-1 $TESTDIR/big-item-1.2
+ storage get-layer-data -f $TESTDIR/big-item-2.2 $layer big-item-2
+ cmp $TESTDIR/big-item-2 $TESTDIR/big-item-2.2
+}
diff --git a/tests/changes.bats b/tests/changes.bats
new file mode 100644
index 0000000..85643ca
--- /dev/null
+++ b/tests/changes.bats
@@ -0,0 +1,30 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "changes" {
+ # Create and populate three interesting layers.
+ populate
+
+ # Mount the layers.
+ run storage --debug=false mount "$lowerlayer"
+ [ "$status" -eq 0 ]
+ lowermount="$output"
+ run storage --debug=false mount "$midlayer"
+ [ "$status" -eq 0 ]
+ midmount="$output"
+ run storage --debug=false mount "$upperlayer"
+ [ "$status" -eq 0 ]
+ uppermount="$output"
+
+ # Check the "changes" output.
+ checkchanges
+
+ # Unmount the layers.
+ storage unmount $lowerlayer
+ storage unmount $midlayer
+ storage unmount $upperlayer
+
+ # Now check the "changes" again.
+ checkchanges
+}
diff --git a/tests/check.bats b/tests/check.bats
new file mode 100644
index 0000000..7f43e34
--- /dev/null
+++ b/tests/check.bats
@@ -0,0 +1,1064 @@
+#!/usr/bin/env bats
+
+load helpers
+
+# Check that the storage driver doesn't have any layers that we don't know
+# about, and would therefore never be able to clean up, i.e., that we can
+# spot them.
+@test "check-unmanaged-layers" {
+ run storage --debug=false storage-layers
+ echo storage-layers: "$output"
+ if [ $status -eq 1 -a "$output" == "driver not supported" ] ; then
+ skip "driver $STORAGE_DRIVER does not support ListLayers()"
+ fi
+
+ run storage --debug=false create-storage-layer
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ run storage create-storage-layer "$layer"
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+
+ run storage create-storage-layer
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer ${layer}: layer in lower level storage driver not accounted for" ]]
+
+ run storage --debug=false storage-layers
+ echo storage-layers: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+}
+
+# Check that nothing happens when the storage driver had layers that we don't
+# know about in a read-only store. It's not as if we can do anything about
+# them.
+@test "check-unmanaged-ro-layers" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Put a couple of unmanaged layers in the read-only location.
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-storage-layer
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-storage-layer "$layer"
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+ otherlayer="$output"
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Put an image in the read-write location.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image "$layer"
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check that we don't complain about unmanaged layers in the read-only location.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo "check:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+}
+
+# Check that the storage driver doesn't have any layers that we don't know
+# about in a read-write store, and would therefore never be able to clean up,
+# i.e., that we can spot them.
+@test "check-unmanaged-rw-layers" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Put an image in the read-only location.
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rolayer=$output
+
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-image "$rolayer"
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Put a couple of unmanaged layers in the read-write location.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-storage-layer
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-storage-layer "$layer"
+ echo create-storage-layer: "$output"
+ [[ $status -eq 0 ]]
+ otherlayer=$output
+
+ # Check that we find the unmanaged layers in the read-write location and remove them.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer ${layer}: layer in lower level storage driver not accounted for" ]]
+ [[ $output =~ "layer ${otherlayer}: layer in lower level storage driver not accounted for" ]]
+
+ # So now there shouldn't be any layers at all if we're just looking at the read-write location.
+ run storage --debug=false storage-layers
+ echo storage-layers: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+
+ # But there should still be that managed layer we put in the read-only location.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layers -q
+ echo storage-layers: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "$rolayer" ]]
+}
+
+# Check that we can detect layers that aren't part of an image or a container.
+@test "check-unused-layers" {
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ run storage --debug=false create-layer $output
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # By default, an unreferenced layer must have reached some minimum age
+ # in order for us to think it's been forgotten.
+ run storage --debug=false check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+
+ # But if we set that minimum age to 0, we should clean it up.
+ run storage check -r -m 0
+ echo "check -r -m 0:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer ${layer}: layer not referenced by any images or containers" ]]
+
+ # After the cleanup, there shouldn't be anything left.
+ run storage --debug=false layers
+ echo layers: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+}
+
+# Check that we don't complain about layers in read-only storage that aren't
+# part of an image or a container, since we can't do anything about them
+# anyway.
+@test "check-unused-ro-layers" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Put a couple of unreferenced layers in the read-only location.
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rolayer="$output"
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer "$rolayer"
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ otherlayer="$output"
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Put an image in the read-write location.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image "$layer"
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check for errors. We shouldn't be warning about the unreferenced read-only layers.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -m 0
+ echo "check -m 0:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+}
+
+# Check that we can detect layers in read-write storage that aren't part of an
+# image or a container.
+@test "check-unused-rw-layers" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Put an image in the read-only location.
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rolayer="$output"
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-image "$rolayer"
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Put some unreferenced layers in the read-write location.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer "$layer"
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ otherlayer=$output
+
+ # By default, an unreferenced layer must have reached some minimum age
+ # in order for us to think it's been forgotten.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+
+ # Now check for errors and repair them.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r -m 0
+ echo "check -r -m 0:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer $layer: layer not referenced by any images or containers" ]]
+ [[ $output =~ "layer $otherlayer: layer not referenced by any images or containers" ]]
+
+ # The read-only layer should be the only one present.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layers -q
+ echo layers: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "$rolayer" ]]
+}
+
+# Check that we can detect when the contents of a layer's files, at least the
+# ones that we'd need to read in order to reconstruct the diff, have been
+# altered.
+@test "check-layer-content-digest" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Set contents of the layer.
+ createrandom ${TESTDIR}/datafile1
+ createrandom ${TESTDIR}/datafile2
+ (cd ${TESTDIR}; tar cf - datafile1 datafile2) > ${TESTDIR}/diff
+ storage apply-diff -f ${TESTDIR}/diff $layer
+
+ # Mark that layer as part of an image.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Put something in the layer that wasn't part of the diff.
+ createrandom ${TESTDIR}/datafile3
+ storage copy ${TESTDIR}/datafile3 ${layer}:/datafile1
+
+ # Now check if the diff can be reproduced correctly.
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer ${layer}: layer content incorrect digest" ]] || [[ $output =~ "layer ${layer}: file integrity checksum failed" ]]
+
+ # Having removed the layer, there should be no traces left.
+ run storage --debug=false images
+ echo images: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+
+ # Should look empty now
+ run storage --debug=false layers
+ echo layers: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output == "" ]]
+}
+
+# Check that we can detect when the contents of a read-only layer's files, at
+# least the ones that we'd need to read in order to reconstruct the diff, have
+# been altered.
+@test "check-ro-layer-content-digest" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Put a layer record in the read-only location.
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rolayer="$output"
+
+ # Set up that layer's contents.
+ createrandom ${TESTDIR}/datafile1
+ createrandom ${TESTDIR}/datafile2
+ (cd ${TESTDIR}; tar cf - datafile1 datafile2) > ${TESTDIR}/diff
+ storage apply-diff --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot -f ${TESTDIR}/diff $rolayer
+
+ # Mess with that layer's contents.
+ createrandom ${TESTDIR}/datafile3
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot copy ${TESTDIR}/datafile3 ${rolayer}:/datafile1
+
+ # Create an image record that uses that layer.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-image "$rolayer"
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a read-write layer.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rwlayer=$output
+
+ # Create a read-write image.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image $rwlayer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check that we notice the added file, even if we can't fix it.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]] # couldn't fix read-only layers
+ [[ $output =~ "layer ${rolayer}: layer content incorrect digest" ]] || [[ $output =~ "layer ${rolayer}: file integrity checksum failed" ]]
+
+ # A check of just the read-write storage shouldn't turn up anything.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect when a layer has had content added. Due to the
+# way diff reconstructs diffs from layers, items which weren't in the original
+# diff won't be noticed if the check consists of only extracting the diff.
+@test "check-layer-content-modified" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ # Create the layer record.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Set up the layer's contents.
+ createrandom ${TESTDIR}/datafile1
+ createrandom ${TESTDIR}/datafile2
+ (cd ${TESTDIR}; tar cf - datafile1 datafile2) > ${TESTDIR}/diff
+ storage apply-diff -f ${TESTDIR}/diff $layer
+
+ # Add some contents to the layer.
+ createrandom ${TESTDIR}/datafile3
+ storage copy ${TESTDIR}/datafile3 ${layer}:/datafile3
+
+ # Create the image record.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check if we can detect that file being added.
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer ${layer}: +/datafile3, layer content modified" ]]
+
+ # Should be all clear now.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect when one of an image's layers is gone, or at least
+# doesn't correspond to one that we know of.
+@test "check-image-layer-missing" {
+ # Create the layer record.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image record.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image="$output"
+
+ # Delete the layer with no safety checking.
+ run storage --debug=false delete $layer
+ echo delete layer: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check that we know to flag the image as damaged, and fix it.
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "image ${image}: layer ${layer}: image layer is missing" ]]
+
+ # Check that we no longer think there's damage.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect when one of an image's layers is gone, or at least
+# doesn't correspond to one that we know of.
+@test "check-ro-image-layer-missing" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Create the read-only layer record.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the read-only image record.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image="$output"
+
+ # Delete the layer with no safety checking.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot delete $layer
+ echo delete layer: "$output"
+ [[ $status -eq 0 ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a read-write layer.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rwlayer=$output
+
+ # Create a read-write image.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image $rwlayer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check that we know to flag the image as damaged, even if we can't fix it.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]] # we can't fix it
+ [[ $output =~ "image ${image}: layer ${layer}: image layer is missing" ]]
+
+ # Check that we no longer think there's damage if we just look at read-write content.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect when a container's base image is gone, or at least
+# doesn't correspond to one that we know of.
+@test "check-container-image-missing" {
+ # Create the layer.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image that uses that layer.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image=$output
+
+ # Create a container based on that image.
+ run storage --debug=false create-container $image
+ echo create-container: "$output"
+ [[ $status -eq 0 ]]
+ container=$output
+
+ # Delete the image with no safety checks.
+ run storage --debug=false delete $image
+ echo delete image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Check and repair. Repair is okay with deleting images because they
+ # can be rebuilt or re-pulled.
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}:" ]]
+ [[ $output =~ "image ${image}: image missing" ]]
+
+ # didn't get rid of the container, though!
+
+ run storage check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}:" ]]
+ [[ $output =~ "image ${image}: image missing" ]]
+
+ # Repair, but now we're okay with getting rid of containers.
+ run storage check -r -f
+ echo "check -r -f:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "container ${container}:" ]]
+ [[ $output =~ "image ${image}: image missing" ]]
+
+ # Should be all clear now.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect when a container's base image is deleted in a
+# read-only store, or at least doesn't correspond to one that we know of.
+@test "check-container-ro-image-missing" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Create the read-only layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the read-only image that uses that layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image=$output
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a container based on that image.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-container $image
+ echo create-container: "$output"
+ [[ $status -eq 0 ]]
+ container=$output
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root container ${container}
+ echo container: "$output"
+ [[ $status -eq 0 ]]
+ clayer=$(grep ^Layer: <<< ${output})
+ clayer=${clayer##* }
+ echo clayer: "${clayer}"
+
+ # Delete the layer with no safety checks.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot delete $layer
+ echo delete layer: "$output"
+ [[ $status -eq 0 ]]
+
+ # Delete the image while we're at it.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot delete $image
+ echo delete image: "$output"
+ [[ $status -eq 0 ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Check and repair. Repair is okay with deleting images because they
+ # can be rebuilt or re-pulled.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}:" ]]
+ [[ $output =~ "image ${image}: image missing" ]]
+ [[ $output =~ "layer ${clayer} used by container ${container}: layer is in use by a container" ]]
+
+ # couldn't get rid of the container, even so
+
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}:" ]]
+ [[ $output =~ "image ${image}: image missing" ]]
+
+ # Repair, but now we're okay with getting rid of damaged containers.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r -f
+ echo "check -r -f:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "container ${container}:" ]]
+ [[ $output =~ "image ${image}: image missing" ]]
+
+ # Should be all clear now.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect layer data being lost.
+@test "check-layer-data-missing" {
+ # Create the layer.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Set a data item associated with the layer.
+ createrandom ${TESTDIR}/datafile
+ storage set-layer-data -f ${TESTDIR}/datafile $layer datafile
+ run storage --debug=false list-layer-data $layer
+ echo list-layer-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look okay.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ # Delete that content and see if we notice.
+ rm -fv ${TESTDIR}/root/${STORAGE_DRIVER}-layers/$layer/datafile
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "layer ${layer}: data item \"datafile\": layer data item is missing" ]]
+
+ # Should have repaired by deleting the image and layer, so we should be
+ # in the clear.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect read-only layer data being lost.
+@test "check-ro-layer-data-missing" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Create the read-only layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Set a data item associated with the layer.
+ createrandom ${TESTDIR}/datafile
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot set-layer-data -f ${TESTDIR}/datafile $layer datafile
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot list-layer-data $layer
+ echo list-layer-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a read-write layer.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rwlayer=$output
+
+ # Create a read-write image.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image $rwlayer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Everything should look okay.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ # Delete that content and see if we notice.
+ rm -fv ${TESTDIR}/ro-root/${STORAGE_DRIVER}-layers/$layer/datafile
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "layer ${layer}: data item \"datafile\": layer data item is missing" ]]
+
+ # Can't repair it by deleting the image and layer, so we should be just
+ # as broken as last time.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "layer ${layer}: data item \"datafile\": layer data item is missing" ]]
+
+ # A check of just the read-write storage shouldn't turn up anything.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect image data being lost.
+@test "check-image-data-missing" {
+ # Create the layer.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image=$output
+
+ # Create the data associated with the image.
+ createrandom ${TESTDIR}/datafile
+ storage set-image-data -f ${TESTDIR}/datafile $image datafile
+ run storage --debug=false list-image-data $image
+ echo list-image-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look good so far.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ # Now delete the data and check that we notice it's gone.
+ rm -fv ${TESTDIR}/root/${STORAGE_DRIVER}-images/$image/datafile
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "image ${image}: data item \"datafile\": image data item is missing" ]]
+
+ # Having repaired it by deleting the offending image, we should be okay again.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect image data in read-only stores being lost.
+@test "check-ro-image-data-missing" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Create the read-only layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image=$output
+
+ # Create the data associated with the image.
+ createrandom ${TESTDIR}/datafile
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot set-image-data -f ${TESTDIR}/datafile $image datafile
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot list-image-data $image
+ echo list-image-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look good so far.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a read-write layer.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rwlayer=$output
+
+ # Create a read-write image.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image $rwlayer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Now delete the data and check that we notice it's gone.
+ rm -fv ${TESTDIR}/ro-root/${STORAGE_DRIVER}-images/$image/datafile
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "image ${image}: data item \"datafile\": image data item is missing" ]]
+
+ # Having been unable to repair it by deleting the offending image, we
+ # should still flag the error.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "image ${image}: data item \"datafile\": image data item is missing" ]]
+
+ # A check of just the read-write storage shouldn't turn up anything.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect image data being modified.
+@test "check-image-data-modified" {
+ # Create the layer.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the image.
+ run storage --debug=false create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image=$output
+
+ # Create some data to associate with the image.
+ createrandom ${TESTDIR}/datafile
+ storage set-image-data -f ${TESTDIR}/datafile $image datafile
+ run storage --debug=false list-image-data $image
+ echo list-image-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look okay so far.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ # Corrupt that data and see if we notice.
+ echo "" >> ${TESTDIR}/root/${STORAGE_DRIVER}-images/$image/datafile
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "image ${image}: data item \"datafile\": image data item has incorrect size" ]]
+
+ # We fixed that by removing the image, so everything should be okay now.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect image data being modified in read-only locations.
+@test "check-ro-image-data-modified" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "driver $STORAGE_DRIVER does not support additional image stores"
+ ;;
+ esac
+
+ # Create the read-only layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ layer=$output
+
+ # Create the read-only image.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image $layer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+ image=$output
+
+ # Create some data to associate with the read-only image.
+ createrandom ${TESTDIR}/datafile
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot set-image-data -f ${TESTDIR}/datafile $image datafile
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot list-image-data $image
+ echo list-image-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look okay so far.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a read-write layer.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rwlayer=$output
+
+ # Create a read-write image.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-image $rwlayer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Corrupt that data and see if we notice.
+ echo "" >> ${TESTDIR}/ro-root/${STORAGE_DRIVER}-images/$image/datafile
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "image ${image}: data item \"datafile\": image data item has incorrect size" ]]
+
+ # We couldn't fix that by removing the image, so we should still notice the problem.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "image ${image}: data item \"datafile\": image data item has incorrect size" ]]
+
+ # A check of just the read-write storage shouldn't turn up anything.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect container data being lost.
+@test "check-container-data-missing" {
+ # Create a container that isn't using an image as its base.
+ run storage --debug=false create-container ""
+ echo create-container: "$output"
+ [[ $status -eq 0 ]]
+ container=$output
+
+ # Store some data alongside the container.
+ createrandom ${TESTDIR}/datafile
+ storage set-container-data -f ${TESTDIR}/datafile $container datafile
+ run storage --debug=false list-container-data $container
+ echo list-container-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look okay so far.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ # Now remove the associated data and see if we notice.
+ rm -fv ${TESTDIR}/root/${STORAGE_DRIVER}-containers/$container/datafile
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}: data item \"datafile\": container data item is missing" ]]
+
+ # didn't get rid of the container, though
+
+ # Should still look broken.
+ run storage check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}: data item \"datafile\": container data item is missing" ]]
+
+ # Now let repair remove containers.
+ run storage check -r -f
+ echo "check -r -f:" "$output"
+ [[ $status -eq 0 ]]
+
+ # Should look okay now.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
+
+# Check that we can detect container data being modified.
+@test "check-container-data-modified" {
+ # Create a container that isn't using an image as its base.
+ run storage --debug=false create-container ""
+ echo create-container: "$output"
+ [[ $status -eq 0 ]]
+ container=$output
+
+ # Store some data alongside the container.
+ createrandom ${TESTDIR}/datafile
+ storage set-container-data -f ${TESTDIR}/datafile $container datafile
+ run storage --debug=false list-container-data $container
+ echo list-container-data: "$output"
+ [[ $status -eq 0 ]]
+ [[ $output != "" ]]
+
+ # Everything should look okay so far.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+
+ # Create a read-write layer.
+ run storage --debug=false create-layer
+ echo create-layer: "$output"
+ [[ $status -eq 0 ]]
+ rwlayer=$output
+
+ # Create a read-write image.
+ run storage --debug=false create-image $rwlayer
+ echo create-image: "$output"
+ [[ $status -eq 0 ]]
+
+ # Now remove the associated data and see if we notice.
+ echo "" >> ${TESTDIR}/root/${STORAGE_DRIVER}-containers/$container/datafile
+ run storage check -r
+ echo "check -r:" "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}: data item \"datafile\": container data item has incorrect size" ]]
+
+ # didn't get rid of the container, though
+
+ # Should still look broken.
+ run storage check
+ echo check: "$output"
+ [[ $status -ne 0 ]]
+ [[ $output =~ "container ${container}: data item \"datafile\": container data item has incorrect size" ]]
+
+ # Now let repair remove containers.
+ run storage check -r -f
+ echo "check -r -f:" "$output"
+ [[ $status -eq 0 ]]
+ [[ $output =~ "container ${container}: data item \"datafile\": container data item has incorrect size" ]]
+
+ # Should look okay now.
+ run storage check
+ echo check: "$output"
+ [[ $status -eq 0 ]]
+}
diff --git a/tests/cleanup-layer.bats b/tests/cleanup-layer.bats
new file mode 100644
index 0000000..813028f
--- /dev/null
+++ b/tests/cleanup-layer.bats
@@ -0,0 +1,17 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "cleanup-layer" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ sed -i -e 's/"id":/"flags":{"incomplete":true},"id":/g' ${TESTDIR}/root/${STORAGE_DRIVER}-layers/layers.json
+
+ # Get a list of the layers, which should clean it up.
+ run storage --debug=false layers
+ [ "$status" -eq 0 ]
+ echo "$output"
+ [ "${#lines[*]}" -eq 0 ]
+}
diff --git a/tests/container-dirs.bats b/tests/container-dirs.bats
new file mode 100644
index 0000000..2cbc237
--- /dev/null
+++ b/tests/container-dirs.bats
@@ -0,0 +1,48 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "container-dirs" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Check that the layer can be found.
+ storage exists -l $layer
+
+ # Create an image using the layer.
+ run storage --debug=false create-image -m danger $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Check that the image can be found.
+ storage exists -i $image
+
+ # Create a container based on the layer.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that the container can be found.
+ storage exists -c $container
+
+ # Check that the container's user data directory is somewhere under the root.
+ run storage --debug=false get-container-dir $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ dir=${output%% *}
+ touch "$dir"/dirfile
+ echo "$dir"/dirfile | grep -q ^"${TESTDIR}/root/"
+
+ # Check that the container's user run data directory is somewhere under the run root.
+ run storage --debug=false get-container-run-dir $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ rundir=${output%% *}
+ touch "$rundir"/rundirfile
+ echo "$rundir"/rundirfile | grep -q ^"${TESTDIR}/runroot/"
+}
diff --git a/tests/container.bats b/tests/container.bats
new file mode 100644
index 0000000..b123807
--- /dev/null
+++ b/tests/container.bats
@@ -0,0 +1,36 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "container" {
+ # Create and populate three interesting layers.
+ populate
+
+ # Create an image using to top layer.
+ run storage --debug=false create-image $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container using the image.
+ name=wonderful-container
+ run storage --debug=false create-container --name $name $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${lines[0]}
+
+ # Add a couple of big data items.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ storage set-container-data -f ${TESTDIR}/random1 $container random1
+ storage set-container-data -f ${TESTDIR}/random2 $container random2
+
+ # Get information about the container, and make sure the ID, name, and data names were preserved.
+ run storage container $container
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "ID: $container" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Data: random1" ]]
+ [[ "$output" =~ "Data: random2" ]]
+}
diff --git a/tests/create-container.bats b/tests/create-container.bats
new file mode 100644
index 0000000..76054c2
--- /dev/null
+++ b/tests/create-container.bats
@@ -0,0 +1,109 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "create-container" {
+ # Create a container based on no image.
+ run storage --debug=false create-container ""
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ zerothcontainer=${output%% *}
+
+ # Create an image using no layer.
+ run storage --debug=false create-image ""
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container based on that image.
+ run storage --debug=false create-container $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ thirdcontainer=${output%% *}
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container based on that image.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ firstcontainer=${output%% *}
+
+ firstwriter=$(cat ${TESTDIR}/${CONTAINERS_LOCK_ROOT}/${STORAGE_DRIVER}-containers/containers.lock)
+ [ "$firstwriter" != "" ]
+
+ # Check that the container can be found.
+ storage exists -c $firstcontainer
+
+ # Create another container based on the same image.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ secondcontainer=${output%% *}
+
+ secondwriter=$(cat ${TESTDIR}/${CONTAINERS_LOCK_ROOT}/${STORAGE_DRIVER}-containers/containers.lock)
+ [ "$secondwriter" != "" ]
+ [ "$firstwriter" != "$secondwriter" ]
+
+ # Check that *that* container can be found.
+ storage exists -c $secondcontainer
+
+ # Check that a list of containers lists both of them.
+ run storage --debug=false containers
+ echo :"$output":
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 4 ]
+ [ "${lines[0]}" != "${lines[1]}" ]
+ [ "${lines[0]}" != "${lines[2]}" ]
+ [ "${lines[0]}" != "${lines[3]}" ]
+ [ "${lines[1]}" != "${lines[2]}" ]
+ [ "${lines[1]}" != "${lines[3]}" ]
+ [ "${lines[2]}" != "${lines[3]}" ]
+ [ "${lines[0]}" = "$zerothcontainer" ] || [ "${lines[0]}" = "$firstcontainer" ] || [ "${lines[0]}" = "$secondcontainer" ] || [ "${lines[0]}" = "$thirdcontainer" ]
+ [ "${lines[1]}" = "$zerothcontainer" ] || [ "${lines[1]}" = "$firstcontainer" ] || [ "${lines[1]}" = "$secondcontainer" ] || [ "${lines[1]}" = "$thirdcontainer" ]
+ [ "${lines[2]}" = "$zerothcontainer" ] || [ "${lines[2]}" = "$firstcontainer" ] || [ "${lines[2]}" = "$secondcontainer" ] || [ "${lines[2]}" = "$thirdcontainer" ]
+ [ "${lines[3]}" = "$zerothcontainer" ] || [ "${lines[3]}" = "$firstcontainer" ] || [ "${lines[3]}" = "$secondcontainer" ] || [ "${lines[3]}" = "$thirdcontainer" ]
+}
+
+@test "create-and-mount-volatile-container" {
+ # Create a container based on no image.
+ run storage --debug=false create-container --volatile ""
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ run storage --debug=false mount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ path=${output%% *}
+
+ echo test > $path/newfile
+
+ run storage --debug=false unmount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+
+ run storage --debug=false mount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ path=${output%% *}
+
+ run cat $path/newfile
+ [ "$status" -eq 0 ]
+ [ "$output" == "test" ]
+
+ run storage --debug=false unmount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+}
diff --git a/tests/create-image.bats b/tests/create-image.bats
new file mode 100644
index 0000000..c8addcd
--- /dev/null
+++ b/tests/create-image.bats
@@ -0,0 +1,54 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "create-image" {
+ # Create an image using no layer.
+ run storage --debug=false create-image ""
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ zerothimage=${output%% *}
+
+ zerothwriter=$(cat ${TESTDIR}/root/${STORAGE_DRIVER}-images/images.lock)
+ [ "$zerothwriter" != "" ]
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ firstimage=${output%% *}
+
+ firstwriter=$(cat ${TESTDIR}/root/${STORAGE_DRIVER}-images/images.lock)
+ [ "$firstwriter" != "" ]
+ [ "$zerothwriter" != "$firstwriter" ]
+
+ # Check that the image can be accessed.
+ storage exists -i $firstimage
+
+ # Create another image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ secondimage=${output%% *}
+
+ # Check that *that* image can be accessed.
+ storage exists -i $secondimage
+
+ # Check that "images" lists the both of the images.
+ run storage --debug=false images
+ [ "$status" -eq 0 ]
+ echo :"$output":
+ [ "${#lines[*]}" -eq 3 ]
+ [ "${lines[0]}" != "${lines[1]}" ]
+ [ "${lines[1]}" != "${lines[2]}" ]
+ [ "${lines[0]}" != "${lines[2]}" ]
+ [ "${lines[0]}" = "$zerothimage" ] || [ "${lines[0]}" = "$firstimage" ] || [ "${lines[0]}" = "$secondimage" ]
+ [ "${lines[1]}" = "$zerothimage" ] || [ "${lines[1]}" = "$firstimage" ] || [ "${lines[1]}" = "$secondimage" ]
+ [ "${lines[2]}" = "$zerothimage" ] || [ "${lines[2]}" = "$firstimage" ] || [ "${lines[2]}" = "$secondimage" ]
+}
diff --git a/tests/create-layer.bats b/tests/create-layer.bats
new file mode 100644
index 0000000..af023f4
--- /dev/null
+++ b/tests/create-layer.bats
@@ -0,0 +1,93 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "create-layer" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ lowerwriter=$(cat ${TESTDIR}/root/${STORAGE_DRIVER}-layers/layers.lock)
+ [ "$lowerwriter" != "" ]
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ lowermwriter=$(cat ${TESTDIR}/runroot/${STORAGE_DRIVER}-layers/mountpoints.lock)
+ [ "$lowermwriter" != "" ]
+ # Put a file in the layer.
+ createrandom "$lowermount"/layer1file1
+
+ # Create a second layer based on the first one.
+ run storage --debug=false create-layer "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midlayer="$output"
+ midwriter=$(cat ${TESTDIR}/root/${STORAGE_DRIVER}-layers/layers.lock)
+ [ "$midwriter" != "" ]
+ # Mount that layer, too.
+ run storage --debug=false mount $midlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midmount="$output"
+ midmwriter=$(cat ${TESTDIR}/runroot/${STORAGE_DRIVER}-layers/mountpoints.lock)
+ [ "$midmwriter" != "" ]
+ # Check that the file from the first layer is there.
+ test -s "$midmount"/layer1file1
+ # Check that we can remove it...
+ rm -f -v "$midmount"/layer1file1
+ # ... and that doing so doesn't affect the first layer.
+ test -s "$lowermount"/layer1file1
+ # Create a new file in this layer.
+ createrandom "$midmount"/layer2file1
+ # Unmount this layer.
+ storage unmount $midlayer
+ # Unmount the first layer.
+ storage unmount $lowerlayer
+
+ # Create a third layer based on the second one.
+ run storage --debug=false create-layer "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ upperwriter=$(cat ${TESTDIR}/root/${STORAGE_DRIVER}-layers/layers.lock)
+ [ "$upperwriter" != "" ]
+ # Mount this layer.
+ run storage --debug=false mount $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+ uppermwriter=$(cat ${TESTDIR}/runroot/${STORAGE_DRIVER}-layers/mountpoints.lock)
+ [ "$uppermwriter" != "" ]
+ # Check that the file we removed from the second layer is still gone.
+ run test -s "$uppermount"/layer1file1
+ [ "$status" -ne 0 ]
+ # Check that the file we added to the second layer is still there.
+ test -s "$uppermount"/layer2file1
+ # Unmount the third layer.
+ storage unmount $upperlayer
+
+ # Get a list of the layers, and make sure all three, and no others, are listed.
+ run storage --debug=false layers
+ [ "$status" -eq 0 ]
+ echo :"$output":
+ [ "${#lines[*]}" -eq 3 ]
+ [ "${lines[0]}" != "${lines[1]}" ]
+ [ "${lines[1]}" != "${lines[2]}" ]
+ [ "${lines[2]}" != "${lines[0]}" ]
+ [ "${lines[0]}" = "$lowerlayer" ] || [ "${lines[0]}" = "$midlayer" ] || [ "${lines[0]}" = "$upperlayer" ]
+ [ "${lines[1]}" = "$lowerlayer" ] || [ "${lines[1]}" = "$midlayer" ] || [ "${lines[1]}" = "$upperlayer" ]
+ [ "${lines[2]}" = "$lowerlayer" ] || [ "${lines[2]}" = "$midlayer" ] || [ "${lines[2]}" = "$upperlayer" ]
+
+ # Check that we updated the layers last-writer consistently.
+ [ "${lowerwriter}" != "${midwriter}" ]
+ [ "${lowerwriter}" != "${upperwriter}" ]
+ [ "${midwriter}" != "${upperwriter}" ]
+
+ # Check that we updated the mountpoints last-writer consistently.
+ [ "${lowermwriter}" != "${midmwriter}" ]
+ [ "${lowermwriter}" != "${uppermwriter}" ]
+ [ "${midmwriter}" != "${uppermwriter}" ]
+}
diff --git a/tests/delete-container.bats b/tests/delete-container.bats
new file mode 100644
index 0000000..d0a927b
--- /dev/null
+++ b/tests/delete-container.bats
@@ -0,0 +1,80 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "delete-container" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create an image using that layer.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that the container can be found.
+ storage exists -c $container
+
+ # Use delete-container to delete it.
+ storage delete-container $container
+
+ # Check that the container is gone.
+ run storage exists -c $container
+ [ "$status" -ne 0 ]
+}
+
+@test "delete-container-with-immutable" {
+ if [ "$OS" != "FreeBSD" ]; then
+ skip "not supported on $OS"
+ fi
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create an image using that layer.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that the container can be found.
+ storage exists -c $container
+
+ run storage --debug=false mount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ containermount="$output"
+
+ # Create a file and make it immutable
+ createrandom "$containermount"/file1
+ chflags schg "$containermount"/file1
+
+ run storage --debug=false unmount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+
+ # Use delete-container to delete it.
+ storage delete-container $container
+
+ # Check that the container is gone.
+ run storage exists -c $container
+ [ "$status" -ne 0 ]
+}
diff --git a/tests/delete-image.bats b/tests/delete-image.bats
new file mode 100644
index 0000000..99f6d10
--- /dev/null
+++ b/tests/delete-image.bats
@@ -0,0 +1,27 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "delete-image" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Check that the image can be found.
+ storage exists -i $image
+
+ # Use delete-image to delete it.
+ storage delete-image $image
+
+ # Check that the image is gone.
+ run storage exists -i $image
+ [ "$status" -ne 0 ]
+}
diff --git a/tests/delete-layer.bats b/tests/delete-layer.bats
new file mode 100644
index 0000000..202bb89
--- /dev/null
+++ b/tests/delete-layer.bats
@@ -0,0 +1,121 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "delete-layer" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Create a random file in the layer.
+ createrandom "$lowermount"/layer1file1
+ # Unmount the layer.
+ storage unmount $lowerlayer
+
+ # Create a second layer based on the first one.
+ run storage --debug=false create-layer "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midlayer="$output"
+ # Mount the second layer.
+ run storage --debug=false mount $midlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midmount="$output"
+ # Make sure the file from the first layer is present in this layer, then remove it.
+ test -s "$midmount"/layer1file1
+ rm -f -v "$midmount"/layer1file1
+ # Create a new file in this layer.
+ createrandom "$midmount"/layer2file1
+ # Unmount the second layer.
+ storage unmount $midlayer
+
+ # Create a third layer based on the second one.
+ run storage --debug=false create-layer "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ # Mount the third layer.
+ run storage --debug=false mount $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+ # Make sure the file from the second layer is present in this layer,
+ # and that the one from the first didn't come back somehow..
+ test -s "$uppermount"/layer2file1
+ run test -s "$uppermount"/layer1file1
+ [ "$status" -ne 0 ]
+ # Unmount the third layer.
+ storage unmount $upperlayer
+
+ # Try to delete the first layer, which should fail because it has children.
+ run storage delete-layer $lowerlayer
+ [ "$status" -ne 0 ]
+ # Try to delete the second layer, which should fail because it has children.
+ run storage delete-layer $midlayer
+ [ "$status" -ne 0 ]
+ # Try to delete the third layer, which should succeed because it has no children.
+ storage delete-layer $upperlayer
+ # Try to delete the second again, and it should succeed because that child is gone.
+ storage delete-layer $midlayer
+ # Try to delete the first again, and it should succeed because that child is gone.
+ storage delete-layer $lowerlayer
+}
+
+@test "delete-layer-with-mappings" {
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ run storage --debug=false create-layer -r
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+
+ run storage --debug=false create-layer -r --uidmap 0:100:100000 --gidmap 0:100:100000 $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer2="$output"
+
+ run storage --debug=false create-layer -r --uidmap 0:200:100000 --gidmap 0:200:100000 $lowerlayer2
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+
+ # Expect an error as both lower layers are referenced
+ run storage --debug=false delete-layer $lowerlayer2
+ [ "$status" -ne 0 ]
+ run storage --debug=false delete-layer $lowerlayer
+ [ "$status" -ne 0 ]
+
+ run storage --debug=false delete-layer $upperlayer
+ [ "$status" -eq 0 ]
+ run storage --debug=false delete-layer $lowerlayer2
+ [ "$status" -eq 0 ]
+
+ run storage --debug=false create-image $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image="$output"
+
+ # The layer is referenced by the image, it cannot be deleted
+ run storage --debug=false delete-layer $upperlayer
+ [ "$status" -ne 0 ]
+
+ run storage --debug=false delete-image $image
+ [ "$status" -eq 0 ]
+}
diff --git a/tests/delete.bats b/tests/delete.bats
new file mode 100644
index 0000000..5dc79c9
--- /dev/null
+++ b/tests/delete.bats
@@ -0,0 +1,47 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "delete" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container based on that image.
+ run storage --debug=false create-container $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that the container can be found, and delete it using the general delete command.
+ storage exists -c $container
+ storage delete $container
+
+ # Check that the container is gone.
+ run storage exists -c $container
+ [ "$status" -ne 0 ]
+
+ # Check that the image can be found, and delete it using the general delete command.
+ storage exists -i $image
+ storage delete $image
+
+ # Check that the image is gone.
+ run storage exists -i $image
+ [ "$status" -ne 0 ]
+
+ # Check that the layer can be found, and delete it using the general delete command.
+ storage exists -l $layer
+ storage delete $layer
+
+ # Check that the layer is gone.
+ run storage exists -l $layer
+ [ "$status" -ne 0 ]
+}
diff --git a/tests/diff.bats b/tests/diff.bats
new file mode 100644
index 0000000..879752e
--- /dev/null
+++ b/tests/diff.bats
@@ -0,0 +1,38 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "diff" {
+ # The checkdiffs function needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ # Create and populate three interesting layers.
+ populate
+
+ # Mount the layers.
+ run storage --debug=false mount "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ run storage --debug=false mount "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midmount="$output"
+ run storage --debug=false mount "$upperlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+
+ # Check the "diff" output.
+ checkdiffs
+
+ # Unmount the layers.
+ storage unmount $lowerlayer
+ storage unmount $midlayer
+ storage unmount $upperlayer
+
+ # Now check the "diff" again.
+ checkdiffs
+}
diff --git a/tests/diffsize.bats b/tests/diffsize.bats
new file mode 100644
index 0000000..d1b35ff
--- /dev/null
+++ b/tests/diffsize.bats
@@ -0,0 +1,22 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "diffsize" {
+ # Create and populate three interesting layers.
+ populate
+
+ # Mount the layers.
+ run storage --debug=false diffsize "$lowerlayer"
+ [ "$status" -eq 0 ]
+ echo size:"$output":
+ [ "$output" -ne 0 ]
+ run storage --debug=false diffsize "$midlayer"
+ [ "$status" -eq 0 ]
+ echo size:"$output":
+ [ "$output" -ne 0 ]
+ run storage --debug=false diffsize "$upperlayer"
+ [ "$status" -eq 0 ]
+ echo size:"$output":
+ [ "$output" -ne 0 ]
+}
diff --git a/tests/helpers.bash b/tests/helpers.bash
new file mode 100755
index 0000000..7f4b401
--- /dev/null
+++ b/tests/helpers.bash
@@ -0,0 +1,332 @@
+#!/usr/bin/env bash
+
+STORAGE_BINARY=${STORAGE_BINARY:-$(dirname ${BASH_SOURCE})/../containers-storage}
+TESTSDIR=${TESTSDIR:-$(dirname ${BASH_SOURCE})}
+STORAGE_DRIVER=${STORAGE_DRIVER:-vfs}
+STORAGE_TRANSIENT=${STORAGE_TRANSIENT:-0}
+STORAGE_OPTION=${STORAGE_OPTION:-}
+PATH=$(dirname ${BASH_SOURCE})/..:${PATH}
+OS=$(uname -s)
+if [ "$STORAGE_TRANSIENT" -eq 1 ]; then
+ CONTAINERS_LOCK_ROOT=runroot
+ STORAGE_TRANSIENT_OPT=--transient-store
+else
+ CONTAINERS_LOCK_ROOT=root
+ STORAGE_TRANSIENT_OPT=""
+fi
+
+# Create a unique root directory and a runroot directory.
+function setup() {
+ suffix=$(dd if=/dev/urandom bs=12 count=1 status=none | base64 | tr +/ABCDEFGHIJKLMNOPQRSTUVWXYZ _.abcdefghijklmnopqrstuvwxyz)
+ TESTDIR=${BATS_TMPDIR}/tmp.${suffix}
+ rm -fr ${TESTDIR}
+ mkdir -p ${TESTDIR}/{root,runroot}
+ # disable idmapped mounts in the overlay driver, since that
+ # is the expectation in the idmaps.bats tests.
+ export _CONTAINERS_OVERLAY_DISABLE_IDMAP=yes
+}
+
+# Delete the unique root directory and a runroot directory.
+function teardown() {
+ run storage wipe
+ if [[ $status -ne 0 ]] ; then
+ echo "$output"
+ fi
+ run storage shutdown
+ if [[ $status -ne 0 ]] ; then
+ echo "$output"
+ fi
+ rm -fr ${TESTDIR}
+}
+
+# Create a file "$1" with random contents of length $2, or 256.
+function createrandom() {
+ output=${1:-${BATS_TMPDIR}/randomfile}
+ dd if=/dev/urandom bs=1 count=${2:-256} of=${output} status=none
+ # Set the mtime to the epoch so it won't be different once it
+ # is deduplicated with OSTree
+ #
+ # Note: The Linux touch utility can express time as an
+ # explicit offset, allowing '@0' as a clear way of expressing
+ # epoch. Unfortunately, the touch utility from BSD derived
+ # platforms including FreeBSD and darwin is more restrictive
+ # so we use ISO 8601 format as lowest common denominator.
+ touch -d 1970-01-01T00:00:00Z ${output}
+}
+
+# Run the CLI with the specified options.
+function storage() {
+ ${STORAGE_BINARY} --debug --graph ${TESTDIR}/root --run ${TESTDIR}/runroot ${STORAGE_TRANSIENT_OPT} --storage-driver ${STORAGE_DRIVER} ${STORAGE_OPTION:+--storage-opt=${STORAGE_OPTION}} "$@"
+}
+
+# Run the CLI with the specified options, and sort its output lines.
+function storagewithsorting() {
+ storage "$@" | LC_ALL=C sort
+}
+
+# Run the CLI with the specified options, and sort its output lines using the second field.
+function storagewithsorting2() {
+ storage "$@" | LC_ALL=C sort -k2
+}
+
+# Create a few layers with files and directories added and removed at each
+# layer. Their IDs are set to $lowerlayer, $midlayer, and $upperlayer.
+populate() {
+ # Create a base layer.
+ run storage --debug=false create-layer
+ echo $output
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ local lowermount="$output"
+ # Create three files, and nine directories: three empty, three with subdirectories, three with files.
+ createrandom "$lowermount"/layer1file1
+ createrandom "$lowermount"/layer1file2
+ createrandom "$lowermount"/layer1file3
+ mkdir "$lowermount"/layerdir1
+ mkdir "$lowermount"/layerdir2
+ mkdir "$lowermount"/layerdir3
+ mkdir "$lowermount"/layerdir4
+ mkdir "$lowermount"/layerdir4/layer1subdir
+ mkdir "$lowermount"/layerdir5
+ mkdir "$lowermount"/layerdir5/layer1subdir
+ mkdir "$lowermount"/layerdir6
+ mkdir "$lowermount"/layerdir6/layer1subdir
+ mkdir "$lowermount"/layerdir7
+ createrandom "$lowermount"/layerdir7/layer1file4
+ mkdir "$lowermount"/layerdir8
+ createrandom "$lowermount"/layerdir8/layer1file5
+ mkdir "$lowermount"/layerdir9
+ createrandom "$lowermount"/layerdir9/layer1file6
+ # Unmount the layer.
+ storage unmount $lowerlayer
+
+ # Create a second layer based on the first.
+ run storage --debug=false create-layer "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midlayer="$output"
+ # Mount the second layer.
+ run storage --debug=false mount $midlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ local midmount="$output"
+ # Check that the files and directories from the first layer are present.
+ test -s "$midmount"/layer1file1
+ test -s "$midmount"/layer1file2
+ test -s "$midmount"/layer1file3
+ test -d "$midmount"/layerdir1
+ test -d "$midmount"/layerdir2
+ test -d "$midmount"/layerdir3
+ test -d "$midmount"/layerdir4
+ test -d "$midmount"/layerdir4/layer1subdir
+ test -d "$midmount"/layerdir5
+ test -d "$midmount"/layerdir5/layer1subdir
+ test -d "$midmount"/layerdir6
+ test -d "$midmount"/layerdir6/layer1subdir
+ test -d "$midmount"/layerdir7
+ test -s "$midmount"/layerdir7/layer1file4
+ test -d "$midmount"/layerdir8
+ test -s "$midmount"/layerdir8/layer1file5
+ test -d "$midmount"/layerdir9
+ test -s "$midmount"/layerdir9/layer1file6
+ # Now remove some of those files and directories.
+ rm "$midmount"/layer1file1
+ rm "$midmount"/layer1file2
+ rmdir "$midmount"/layerdir1
+ rmdir "$midmount"/layerdir2
+ rmdir "$midmount"/layerdir4/layer1subdir
+ rmdir "$midmount"/layerdir4
+ rmdir "$midmount"/layerdir5/layer1subdir
+ rmdir "$midmount"/layerdir5
+ rm "$midmount"/layerdir7/layer1file4
+ rmdir "$midmount"/layerdir7
+ rm "$midmount"/layerdir8/layer1file5
+ rmdir "$midmount"/layerdir8
+ # Add a couple of new files and directories.
+ createrandom "$midmount"/layer2file1
+ mkdir "$midmount"/layerdir10
+ mkdir "$midmount"/layerdir11
+ mkdir "$midmount"/layerdir11/layer2subdir
+ mkdir "$midmount"/layerdir12
+ createrandom "$midmount"/layerdir12/layer2file2
+ # Unmount the layer.
+ storage unmount $midlayer
+
+ # Create a third layer based on the second.
+ run storage --debug=false create-layer "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ # Mount the third layer.
+ run storage --debug=false mount $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ local uppermount="$output"
+ # Check that contents of the second layer are present.
+ test -s "$uppermount"/layer1file3
+ test -d "$uppermount"/layerdir3
+ test -d "$uppermount"/layerdir6
+ test -d "$uppermount"/layerdir6/layer1subdir
+ test -d "$uppermount"/layerdir9
+ test -s "$uppermount"/layerdir9/layer1file6
+ test -s "$uppermount"/layer2file1
+ test -d "$uppermount"/layerdir10
+ test -d "$uppermount"/layerdir11
+ test -d "$uppermount"/layerdir11/layer2subdir
+ test -d "$uppermount"/layerdir12
+ test -s "$uppermount"/layerdir12/layer2file2
+ # Re-add some contents for this layer that were removed earlier.
+ createrandom "$uppermount"/layerfile1
+ mkdir "$uppermount"/layerdir1
+ mkdir "$uppermount"/layerdir4
+ mkdir "$uppermount"/layerdir4/layer1subdir
+ mkdir "$uppermount"/layerdir7
+ # Add some new contents, too.
+ mkdir "$uppermount"/layerdir3/layer3subdir
+ mkdir "$uppermount"/layerdir3/layer3subdir/layer3subsubdir
+ createrandom "$uppermount"/layerdir7/layer1file4
+ # Unmount the layer.
+ storage unmount $upperlayer
+}
+
+# Check that the changes list for layers created by populate() correspond to
+# what naive diff methods would generate.
+checkchanges() {
+ # The first layer should all be additions.
+ storage changes $lowerlayer
+ run storagewithsorting2 --debug=false changes $lowerlayer
+ [ "$status" -eq 0 ]
+ echo Changes for layer 1:
+ echo "$output"
+ [ "${#lines[*]}" -eq 18 ]
+ [ "${lines[0]}" = 'Add "/layer1file1"' ]
+ [ "${lines[1]}" = 'Add "/layer1file2"' ]
+ [ "${lines[2]}" = 'Add "/layer1file3"' ]
+ [ "${lines[3]}" = 'Add "/layerdir1"' ]
+ [ "${lines[4]}" = 'Add "/layerdir2"' ]
+ [ "${lines[5]}" = 'Add "/layerdir3"' ]
+ [ "${lines[6]}" = 'Add "/layerdir4"' ]
+ [ "${lines[7]}" = 'Add "/layerdir4/layer1subdir"' ]
+ [ "${lines[8]}" = 'Add "/layerdir5"' ]
+ [ "${lines[9]}" = 'Add "/layerdir5/layer1subdir"' ]
+ [ "${lines[10]}" = 'Add "/layerdir6"' ]
+ [ "${lines[11]}" = 'Add "/layerdir6/layer1subdir"' ]
+ [ "${lines[12]}" = 'Add "/layerdir7"' ]
+ [ "${lines[13]}" = 'Add "/layerdir7/layer1file4"' ]
+ [ "${lines[14]}" = 'Add "/layerdir8"' ]
+ [ "${lines[15]}" = 'Add "/layerdir8/layer1file5"' ]
+ [ "${lines[16]}" = 'Add "/layerdir9"' ]
+ [ "${lines[17]}" = 'Add "/layerdir9/layer1file6"' ]
+ # Check the second layer.
+ storage changes $midlayer
+ run storagewithsorting2 --debug=false changes $midlayer
+ [ "$status" -eq 0 ]
+ echo Changes for layer 2:
+ echo "$output"
+ [ "${#lines[*]}" -eq 14 ]
+ [ "${lines[0]}" = 'Delete "/layer1file1"' ]
+ [ "${lines[1]}" = 'Delete "/layer1file2"' ]
+ [ "${lines[2]}" = 'Add "/layer2file1"' ]
+ [ "${lines[3]}" = 'Delete "/layerdir1"' ]
+ [ "${lines[4]}" = 'Add "/layerdir10"' ]
+ [ "${lines[5]}" = 'Add "/layerdir11"' ]
+ [ "${lines[6]}" = 'Add "/layerdir11/layer2subdir"' ]
+ [ "${lines[7]}" = 'Add "/layerdir12"' ]
+ [ "${lines[8]}" = 'Add "/layerdir12/layer2file2"' ]
+ [ "${lines[9]}" = 'Delete "/layerdir2"' ]
+ [ "${lines[10]}" = 'Delete "/layerdir4"' ]
+ [ "${lines[11]}" = 'Delete "/layerdir5"' ]
+ [ "${lines[12]}" = 'Delete "/layerdir7"' ]
+ [ "${lines[13]}" = 'Delete "/layerdir8"' ]
+ # Check the third layer.
+ storage changes $upperlayer
+ run storagewithsorting2 --debug=false changes $upperlayer
+ [ "$status" -eq 0 ]
+ echo Changes for layer 3:
+ echo "$output"
+ [ "${#lines[*]}" -eq 9 ]
+ [ "${lines[0]}" = 'Add "/layerdir1"' ]
+ [ "${lines[1]}" = 'Modify "/layerdir3"' ]
+ [ "${lines[2]}" = 'Add "/layerdir3/layer3subdir"' ]
+ [ "${lines[3]}" = 'Add "/layerdir3/layer3subdir/layer3subsubdir"' ]
+ [ "${lines[4]}" = 'Add "/layerdir4"' ]
+ [ "${lines[5]}" = 'Add "/layerdir4/layer1subdir"' ]
+ [ "${lines[6]}" = 'Add "/layerdir7"' ]
+ [ "${lines[7]}" = 'Add "/layerdir7/layer1file4"' ]
+ [ "${lines[8]}" = 'Add "/layerfile1"' ]
+}
+
+# Check that the diff contents for layers created by populate() correspond to
+# what naive diff methods would generate.
+checkdiffs() {
+ # The first layer should all be additions.
+ storage diff -u -f $TESTDIR/lower.tar $lowerlayer
+ tar tf $TESTDIR/lower.tar > $TESTDIR/lower.txt
+ run env LC_ALL=C sort $TESTDIR/lower.txt
+ [ "$status" -eq 0 ]
+ echo Diff contents for layer 1:
+ echo "$output"
+ [ "${#lines[*]}" -eq 18 ]
+ [ "${lines[0]}" = 'layer1file1' ]
+ [ "${lines[1]}" = 'layer1file2' ]
+ [ "${lines[2]}" = 'layer1file3' ]
+ [ "${lines[3]}" = 'layerdir1/' ]
+ [ "${lines[4]}" = 'layerdir2/' ]
+ [ "${lines[5]}" = 'layerdir3/' ]
+ [ "${lines[6]}" = 'layerdir4/' ]
+ [ "${lines[7]}" = 'layerdir4/layer1subdir/' ]
+ [ "${lines[8]}" = 'layerdir5/' ]
+ [ "${lines[9]}" = 'layerdir5/layer1subdir/' ]
+ [ "${lines[10]}" = 'layerdir6/' ]
+ [ "${lines[11]}" = 'layerdir6/layer1subdir/' ]
+ [ "${lines[12]}" = 'layerdir7/' ]
+ [ "${lines[13]}" = 'layerdir7/layer1file4' ]
+ [ "${lines[14]}" = 'layerdir8/' ]
+ [ "${lines[15]}" = 'layerdir8/layer1file5' ]
+ [ "${lines[16]}" = 'layerdir9/' ]
+ [ "${lines[17]}" = 'layerdir9/layer1file6' ]
+ # Check the second layer.
+ storage diff -c -f $TESTDIR/middle.tar $midlayer
+ tar tzf $TESTDIR/middle.tar > $TESTDIR/middle.txt
+ run env LC_ALL=C sort $TESTDIR/middle.txt
+ [ "$status" -eq 0 ]
+ echo Diff contents for layer 2:
+ echo "$output"
+ [ "${#lines[*]}" -eq 14 ]
+ [ "${lines[0]}" = '.wh.layer1file1' ]
+ [ "${lines[1]}" = '.wh.layer1file2' ]
+ [ "${lines[2]}" = '.wh.layerdir1' ]
+ [ "${lines[3]}" = '.wh.layerdir2' ]
+ [ "${lines[4]}" = '.wh.layerdir4' ]
+ [ "${lines[5]}" = '.wh.layerdir5' ]
+ [ "${lines[6]}" = '.wh.layerdir7' ]
+ [ "${lines[7]}" = '.wh.layerdir8' ]
+ [ "${lines[8]}" = 'layer2file1' ]
+ [ "${lines[9]}" = 'layerdir10/' ]
+ [ "${lines[10]}" = 'layerdir11/' ]
+ [ "${lines[11]}" = 'layerdir11/layer2subdir/' ]
+ [ "${lines[12]}" = 'layerdir12/' ]
+ [ "${lines[13]}" = 'layerdir12/layer2file2' ]
+ # Check the third layer.
+ storage diff -u -f $TESTDIR/upper.tar $upperlayer
+ tar tf $TESTDIR/upper.tar > $TESTDIR/upper.txt
+ run env LC_ALL=C sort $TESTDIR/upper.txt
+ [ "$status" -eq 0 ]
+ echo Diff contents for layer 3:
+ echo "$output"
+ [ "${#lines[*]}" -eq 9 ]
+ [ "${lines[0]}" = 'layerdir1/' ]
+ [ "${lines[1]}" = 'layerdir3/' ]
+ [ "${lines[2]}" = 'layerdir3/layer3subdir/' ]
+ [ "${lines[3]}" = 'layerdir3/layer3subdir/layer3subsubdir/' ]
+ [ "${lines[4]}" = 'layerdir4/' ]
+ [ "${lines[5]}" = 'layerdir4/layer1subdir/' ]
+ [ "${lines[6]}" = 'layerdir7/' ]
+ [ "${lines[7]}" = 'layerdir7/layer1file4' ]
+ [ "${lines[8]}" = 'layerfile1' ]
+}
diff --git a/tests/idmaps.bats b/tests/idmaps.bats
new file mode 100644
index 0000000..470dd1b
--- /dev/null
+++ b/tests/idmaps.bats
@@ -0,0 +1,1050 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "idmaps-create-apply-layer" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+
+ n=5
+ host=2
+
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ chown ${i}:${i} "$TESTDIR"/file$i
+ ln -s . $TESTDIR/subdir$i
+ done
+ # Use them to create some diffs.
+ pushd $TESTDIR > /dev/null
+ for i in $(seq $n) ; do
+ tar cf diff${i}.tar subdir$i/
+ done
+ popd > /dev/null
+ # Select some ID ranges.
+ for i in $(seq $n) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ done
+ # Create a layer using the host's mappings.
+ run storage --debug=false create-layer --hostuidmap --hostgidmap
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Copy the files in (host mapping, so it's fine), and set ownerships on them.
+ cp -p "$TESTDIR"/file1 ${lowermount}
+ cp -p "$TESTDIR"/file2 ${lowermount}
+ cp -p "$TESTDIR"/file3 ${lowermount}
+ cp -p "$TESTDIR"/file4 ${lowermount}
+ cp -p "$TESTDIR"/file5 ${lowermount}
+
+ # Create a hard link
+ createrandom ${lowermount}/origin-file
+ ln ${lowermount}/origin-file ${lowermount}/ln-file
+
+ # Create new layers.
+ for i in $(seq $n) ; do
+ if test $host -ne $i ; then
+ run storage --debug=false create-layer --uidmap 0:${uidrange[$i]}:$(($n+1)) --gidmap 0:${gidrange[$i]}:$(($n+1)) $lowerlayer
+ else
+ uidrange[$host]=0
+ gidrange[$host]=0
+ run storage --debug=false create-layer --hostuidmap --hostgidmap $lowerlayer
+ fi
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ run storage --debug=false mount $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+ run storage --debug=false apply-diff $upperlayer < ${TESTDIR}/diff${i}.tar
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" = "" ]
+
+ # Verify that the hard link is maintained
+ origin_ino=$(stat -c %i ${uppermount}/origin-file)
+ ln_ino=$(stat -c %i ${uppermount}/ln-file)
+ echo test ${origin_ino} = ${ln_ino}
+ test ${origin_ino} = ${ln_ino}
+
+ for j in $(seq $n) ; do
+ # Check the inherited original files.
+ cmp ${uppermount}/file$j "$TESTDIR"/file$j
+ uid=$(stat -c %u ${uppermount}/file$j)
+ gid=$(stat -c %g ${uppermount}/file$j)
+ echo test found ${uid}:${gid} = expected $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j)) for file$j
+ test ${uid}:${gid} = $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j))
+ # Check the inherited/current layer's diff files.
+ for k in $(seq $i) ; do
+ cmp ${uppermount}/subdir$k/file$j "$TESTDIR"/file$j
+ uid=$(stat -c %u ${uppermount}/subdir$k/file$j)
+ gid=$(stat -c %g ${uppermount}/subdir$k/file$j)
+ echo test found ${uid}:${gid} = expected $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j)) for subdir$k/file$j
+ test ${uid}:${gid} = $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j))
+ done
+ done
+ lowerlayer=$upperlayer
+ done
+}
+
+@test "idmaps-create-diff-layer" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ n=5
+ host=2
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ done
+ # Select some ID ranges.
+ for i in 0 $(seq $n) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ done
+ # Create a layer using some random mappings.
+ run storage --debug=false create-layer --uidmap 0:${uidrange[0]}:$(($n+1)) --gidmap 0:${gidrange[0]}:$(($n+1))
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Copy the files in, and set ownerships on them.
+ for i in $(seq $n) ; do
+ cp "$TESTDIR"/file$i ${lowermount}
+ chown $((${uidrange[0]}+$i)):$((${gidrange[0]}+$i)) ${lowermount}/file$i
+ done
+ # Create new layers.
+ for i in $(seq $n) ; do
+ if test $host -ne $i ; then
+ run storage --debug=false create-layer --uidmap 0:${uidrange[$i]}:$(($n+1)) --gidmap 0:${gidrange[$i]}:$(($n+1)) $lowerlayer
+ else
+ uidrange[$host]=0
+ gidrange[$host]=0
+ run storage --debug=false create-layer --hostuidmap --hostgidmap $lowerlayer
+ fi
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ run storage --debug=false mount $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+ # Change the owner of one file to 0:0.
+ chown ${uidrange[$i]}:${gidrange[$i]} ${uppermount}/file$i
+ # Verify that the file is the only thing that shows up in a change list.
+ run storage --debug=false changes $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ [ "${#lines[*]}" -eq 1 ]
+ [ "$output" = "Modify \"/file$i\"" ]
+ # Verify that the file is the only thing that shows up in a diff.
+ run storage --debug=false diff -f $TESTDIR/diff.tar $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run tar tf $TESTDIR/diff.tar
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ [ "${#lines[*]}" -eq 1 ]
+ [ "$output" = file$i ]
+ # Check who owns that file, according to the diff.
+ mkdir "$TESTDIR"/subdir$i
+ pushd "$TESTDIR"/subdir$i > /dev/null
+ run tar xf $TESTDIR/diff.tar
+ [ "$status" -eq 0 ]
+ run stat -c %u:%g file$i
+ [ "$status" -eq 0 ]
+ [ "$output" = 0:0 ]
+ popd > /dev/null
+ lowerlayer=$upperlayer
+ done
+}
+
+@test "idmaps-create-container" {
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ n=5
+ host=2
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ done
+ # Select some ID ranges.
+ for i in 0 $(seq $(($n+1))) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ done
+ # Create a layer using some random mappings.
+ run storage --debug=false create-layer --uidmap 0:${uidrange[0]}:$(($n+1)) --gidmap 0:${gidrange[0]}:$(($n+1))
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Copy the files in, and set ownerships on them.
+ for i in $(seq $n) ; do
+ cp "$TESTDIR"/file$i ${lowermount}
+ chown $((${uidrange[0]}+$i)):$((${gidrange[0]}+$i)) ${lowermount}/file$i
+ done
+ # Create new layers.
+ for i in $(seq $n) ; do
+ if test $host -ne $i ; then
+ run storage --debug=false create-layer --uidmap 0:${uidrange[$i]}:$(($n+1)) --gidmap 0:${gidrange[$i]}:$(($n+1)) $lowerlayer
+ else
+ uidrange[$host]=0
+ gidrange[$host]=0
+ run storage --debug=false create-layer --hostuidmap --hostgidmap $lowerlayer
+ fi
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ run storage --debug=false mount $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+ # Change the owner of one file to 0:0.
+ chown ${uidrange[$i]}:${gidrange[$i]} ${uppermount}/file$i
+ # Verify that the file is the only thing that shows up in a change list.
+ run storage --debug=false changes $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ [ "${#lines[*]}" -eq 1 ]
+ [ "$output" = "Modify \"/file$i\"" ]
+ lowerlayer=$upperlayer
+ done
+ # Create new containers based on the layer.
+ imagename=idmappedimage
+ storage create-image --name=$imagename $lowerlayer
+
+ run storage --debug=false create-container --hostuidmap --hostgidmap $imagename
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ hostcontainer="$output"
+ run storage --debug=false mount $hostcontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ hostmount="$output"
+ for i in $(seq $n) ; do
+ run stat -c %u:%g "$hostmount"/file$i
+ [ "$status" -eq 0 ]
+ [ "$output" = 0:0 ]
+ done
+
+ run storage --debug=false create-container --hostuidmap --hostgidmap $imagename
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ hostcontainer="$output"
+ run storage --debug=false mount $hostcontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ hostmount="$output"
+ for i in $(seq $n) ; do
+ run stat -c %u:%g "$hostmount"/file$i
+ [ "$status" -eq 0 ]
+ [ "$output" = 0:0 ]
+ done
+
+ run storage --debug=false create-container --uidmap 0:${uidrange[$(($n+1))]}:$(($n+1)) --gidmap 0:${gidrange[$(($n+1))]}:$(($n+1)) $imagename
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ newmapcontainer="$output"
+ run storage --debug=false mount $newmapcontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ newmapmount="$output"
+ for i in $(seq $n) ; do
+ run stat -c %u:%g "$newmapmount"/file$i
+ [ "$status" -eq 0 ]
+ [ "$output" = ${uidrange[$(($n+1))]}:${gidrange[$(($n+1))]} ]
+ done
+
+ run storage --debug=false create-container $imagename
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ defmapcontainer="$output"
+ run storage --debug=false mount $defmapcontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ defmapmount="$output"
+ for i in $(seq $n) ; do
+ run stat -c %u:%g "$defmapmount"/file$i
+ [ "$status" -eq 0 ]
+ [ "$output" = "0:0" ]
+ done
+}
+
+@test "idmaps-parent-owners" {
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ n=5
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ done
+ # Select some ID ranges.
+ uidrange=$((($RANDOM+32767)*65536))
+ gidrange=$((($RANDOM+32767)*65536))
+ # Create a layer using some random mappings.
+ run storage --debug=false create-layer --uidmap 0:${uidrange}:$(($n+1)) --gidmap 0:${gidrange}:$(($n+1))
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer="$output"
+ # Mount the layer.
+ run storage mount $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ # Check who owns the parent directories.
+ run storage --debug=false layer-parent-owners $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ # Assume that except for root and maybe us, there are no other owners of parent directories of our layer.
+ if ! fgrep -q 'UIDs: [0]' <<< "$output" ; then
+ fgrep -q 'UIDs: [0, '$(id -u)']' <<< "$output"
+ fi
+ if ! fgrep -q 'GIDs: [0]' <<< "$output" ; then
+ fgrep -q 'GIDs: [0, '$(id -g)']' <<< "$output"
+ fi
+ # Create a new container based on the layer.
+ imagename=idmappedimage
+ storage create-image --name=$imagename $layer
+ run storage --debug=false create-container $imagename
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container="$output"
+ # Mount the container.
+ run storage mount $container
+ echo "$output"
+ [ "$status" -eq 0 ]
+ # Check who owns the parent directories.
+ run storage --debug=false container-parent-owners $container
+ [ "$status" -eq 0 ]
+ cat <<< "$output" | tr '\n' '_'
+ # Check there are no unmapped IDs
+ fgrep -q 'UIDs: []' <<< "$output"
+ fgrep -q 'GIDs: []' <<< "$output"
+}
+
+@test "idmaps-copy" {
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ n=5
+ host=2
+ # Create some temporary files.
+ mkdir -p "$TESTDIR"/subdir/subdir2
+ for i in 0 $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ chown "$i":"$i" "$TESTDIR"/file$i
+ createrandom "$TESTDIR"/subdir/subdir2/file$i
+ chown "$i":"$i" "$TESTDIR"/subdir/subdir2/file$i
+ done
+ chown "$(($n+1))":"$(($n+1))" "$TESTDIR"/subdir/subdir2
+ # Select some ID ranges for ID mappings.
+ for i in 0 $(seq $(($n+1))) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ # Create a layer using some those mappings.
+ run storage --debug=false create-layer --uidmap 0:${uidrange[$i]}:101 --gidmap 0:${gidrange[$i]}:101
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer[$i]="$output"
+ done
+ # Copy the file in, and check that its ownerships get mapped correctly.
+ for i in 0 $(seq $n) ; do
+ run storage copy "$TESTDIR"/file$i ${layer[$i]}:/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run storage --debug=false mount ${layer[$i]}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ mnt[$i]="$output"
+ run stat -c "%u:%g" ${mnt[$i]}/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+$i))
+ gid=$((${gidrange[$i]}+$i))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+ # Try copying with --chown.
+ run storage copy --chown 100:100 "$TESTDIR"/file$i ${layer[$i]}:/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run storage --debug=false mount ${layer[$i]}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ mnt[$i]="$output"
+ run stat -c "%u:%g" ${mnt[$i]}/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+100))
+ gid=$((${gidrange[$i]}+100))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+ done
+ # Copy the subdirectory, and check that its ownerships and that of its contents get mapped correctly.
+ for i in 0 $(seq $n) ; do
+ run storage copy "$TESTDIR"/file$i ${layer[$i]}:/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run stat -c "%u:%g" ${mnt[$i]}/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+$i))
+ gid=$((${gidrange[$i]}+$i))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+
+ # Try copying with --chown.
+ run storage copy --chown 100:100 "$TESTDIR"/file$i ${layer[$i]}:/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run stat -c "%u:%g" ${mnt[$i]}/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+100))
+ gid=$((${gidrange[$i]}+100))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+
+ # Try copying a directory tree.
+ run storage copy "$TESTDIR"/subdir ${layer[$i]}:/subdir
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run stat -c "%u:%g" ${mnt[$i]}/subdir/subdir2/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+$i))
+ gid=$((${gidrange[$i]}+$i))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+ run stat -c "%u:%g" ${mnt[$i]}/subdir/subdir2
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+$n+1))
+ gid=$((${gidrange[$i]}+$n+1))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+
+ # Try copying a directory tree with --chown.
+ run storage copy --chown 100:100 "$TESTDIR"/subdir ${layer[$i]}:/subdir2
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run stat -c "%u:%g" ${mnt[$i]}/subdir2/subdir2/file$i
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+100))
+ gid=$((${gidrange[$i]}+100))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+ run stat -c "%u:%g" ${mnt[$i]}/subdir2/subdir2
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$i]}+100))
+ gid=$((${gidrange[$i]}+100))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+ done
+
+ # Copy a file out of a layer, into another one.
+ run storage copy "$TESTDIR"/file$n ${layer[0]}:/file$n
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run storage copy ${layer[0]}:/file$n ${layer[$n]}:/file$n
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run stat -c "%u:%g" ${mnt[$n]}/file$n
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$n]}+$n))
+ gid=$((${gidrange[$n]}+$n))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+
+ # Try copying a directory tree.
+ run storage copy ${layer[0]}:/subdir ${layer[$n]}:/subdir
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run stat -c "%u:%g" ${mnt[$n]}/subdir/subdir2/file$n
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$n]}+$n))
+ gid=$((${gidrange[$n]}+$n))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+ run stat -c "%u:%g" ${mnt[$n]}/subdir/subdir2
+ echo "$output"
+ [ "$status" -eq 0 ]
+ uid=$((${uidrange[$n]}+$n+1))
+ gid=$((${gidrange[$n]}+$n+1))
+ echo comparing "$output" and "$uid:$gid"
+ [ "$output" == "$uid:$gid" ]
+}
+
+@test "idmaps-create-mapped-image" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ btrfs|devicemapper|overlay*|vfs|zfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ n=5
+ host=2
+ filelist=
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ chown ${i}:${i} "$TESTDIR"/file$i
+ filelist="$filelist file$i"
+ done
+ # Select some ID ranges.
+ for i in $(seq $n) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ done
+ # Create a base layer using the host's mappings.
+ run storage --debug=false create-layer --hostuidmap --hostgidmap
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ baselayer="$output"
+ # Create an empty layer blob and apply it to the layer.
+ dd if=/dev/zero bs=1k count=1 of="$TESTDIR"/layer.empty
+ run storage --debug=false applydiff -f "$TESTDIR"/layer.empty $baselayer
+ # Create a layer using the host's mappings.
+ run storage --debug=false create-layer --hostuidmap --hostgidmap $baselayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Create a layer blob containing the files and apply it to the layer.
+ tar --directory "$TESTDIR" -cvf "$TESTDIR"/layer.tar $filelist
+ run storage --debug=false applydiff -f "$TESTDIR"/layer.tar $lowerlayer
+ # Create an image record for this layer.
+ run storage --debug=false create-image $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image="$output"
+ echo image:$image
+ # Check that we can compute the size of the image.
+ run storage --debug=false image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ size=$(grep ^Size: <<< "$output" | sed 's,^Size: ,,g')
+ [ "$size" -ne 0 ]
+ echo size:$size
+ # Create containers using this image.
+ containers=
+ for i in $(seq $n) ; do
+ if test $host -ne $i ; then
+ run storage --debug=false create-container --uidmap 0:${uidrange[$i]}:$(($n+1)) --gidmap 0:${gidrange[$i]}:$(($n+1)) $image
+ else
+ uidrange[$host]=0
+ gidrange[$host]=0
+ run storage --debug=false create-container --hostuidmap --hostgidmap $image
+ fi
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${lines[0]}
+ containers[$i-1]="$container"
+
+ # Check that the ownerships came out right.
+ run storage --debug=false mount "$container"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ mount="$output"
+
+ for j in $(seq $n) ; do
+ ownerids=$(stat -c %u:%g ${mount}/file$j)
+ echo on-disk IDs: "$ownerids"
+ echo expected IDs: $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j))
+ [ "$ownerids" = $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j)) ]
+ done
+ run storage --debug=false unmount "$container"
+ [ "$status" -eq 0 ]
+ done
+ # Each of the containers' layers should have a different parent layer,
+ # all of which should be a top layer for the image. The containers
+ # themselves have no contents at this point.
+ declare -a parents
+ echo containers list is \"${containers[*]}\"
+ for container in "${containers[@]}" ; do
+ run storage --debug=false container $container
+ echo container "$container":"$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ baseimage=$(grep ^Image: <<< "$output" | sed 's,^Image: ,,g')
+ echo baseimage:"$baseimage"
+ [ "$baseimage" = "$image" ]
+ layer=$(grep ^Layer: <<< "$output" | sed 's,^Layer: ,,g')
+ echo layer:"$layer"
+ size=$(grep ^Size: <<< "$output" | sed 's,^Size: ,,g')
+ [ "$size" -eq 0 ]
+ echo size:$size
+
+ run storage --debug=false layer $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ parent=$(grep ^Parent: <<< "$output" | sed 's,^Parent: ,,g')
+ echo parent:"$parent"
+
+ parents[${#parents[*]}]="$parent"
+
+ run storage --debug=false image $baseimage
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ grep "^Top Layer: $parent" <<< "$output"
+ done
+ nparents=$(for p in ${parents[@]} ; do echo $p ; done | sort -u | wc -l)
+ echo nparents:$nparents
+ [ $nparents -eq $n ]
+
+ # The image should have five top layers at this point, they should all
+ # have known sizes, and we should be able to diff them all.
+ run storage --debug=false image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ tops=$(grep '^Top Layer:' <<< "$output" | sed 's,^Top Layer: ,,g')
+ echo tops: "$tops"
+ ntops=$(for p in $tops; do echo $p ; done | sort -u | wc -l)
+ echo ntops:$ntops
+ [ $ntops -eq $n ]
+ for p in $tops; do
+ rm -f "$TESTDIR"/diff.tar
+ storage --debug=false diff -u -f "$TESTDIR"/diff.tar "$p"
+ test -s "$TESTDIR"/diff.tar
+ expected=$(storage --debug=false layer --json $p | sed -r -e 's|.*"diff-size":([^",]*).*|\1|g')
+ actual=$(stat -c %s "$TESTDIR"/diff.tar)
+ echo expected diff size "$expected", got "$actual"
+ test $actual = $expected
+ expected=$(storage --debug=false layer --json $p | sed -r -e 's|.*"diff-digest":"?([^",]*).*|\1|g')
+ actual=sha256:$(sha256sum "$TESTDIR"/diff.tar | sed -e 's, .*,,g')
+ echo expected diff digest "$expected", got "$actual"
+ test $actual = $expected
+ done
+
+ # Create a new layer based on the image.
+ run storage --debug=false create-layer --hostuidmap --hostgidmap $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ run storage --debug=false applydiff -f "$TESTDIR"/layer.empty $upperlayer
+ # Create an image record for the new layer.
+ run storage --debug=false create-image $upperlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperimage="$output"
+ echo upperimage:$upperimage
+
+ # Remove the containers and images and check that all of the layers we used got removed.
+ for container in "${containers[@]}" ; do
+ run storage --debug=false delete-container $container
+ done
+ run storage --debug=false delete-image $image
+ run storage --debug=false delete-image $upperimage
+ run storage --debug=false layers
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" == "" ]
+}
+
+@test "idmaps-create-mapped-container" {
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "${STORAGE_DRIVER}.imagestore option not supported by driver ${STORAGE_DRIVER}"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+ n=5
+ host=2
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ chown ${i}:${i} "$TESTDIR"/file$i
+ done
+ # Select some ID ranges.
+ for i in $(seq $n) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ done
+ # Create a base layer using the host's mappings.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer --hostuidmap --hostgidmap
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ baselayer="$output"
+ # Create a layer using the host's mappings.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer --hostuidmap --hostgidmap $baselayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot mount $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Copy the files in (host mapping, so it's fine), and set ownerships on them.
+ cp -p "$TESTDIR"/file1 ${lowermount}
+ cp -p "$TESTDIR"/file2 ${lowermount}
+ cp -p "$TESTDIR"/file3 ${lowermount}
+ cp -p "$TESTDIR"/file4 ${lowermount}
+ cp -p "$TESTDIR"/file5 ${lowermount}
+ # Unmount the layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot unmount $lowerlayer
+ [ "$status" -eq 0 ]
+ # Create an image record for this layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image $lowerlayer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image="$output"
+ echo image:$image
+ # Check that we can compute the size of the image.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ size=$(grep ^Size: <<< "$output" | sed 's,^Size: ,,g')
+ [ "$size" -ne 0 ]
+ echo size:$size
+ # Done using this location directly.
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+ # Create containers using this image.
+ containers=
+ for i in $(seq $n) ; do
+ if test $host -ne $i ; then
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-container --uidmap 0:${uidrange[$i]}:$(($n+1)) --gidmap 0:${gidrange[$i]}:$(($n+1)) $image
+ else
+ uidrange[$host]=0
+ gidrange[$host]=0
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root create-container --hostuidmap --hostgidmap $image
+ fi
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${lines[0]}
+ containers[$i-1]="$container"
+
+ # Check that the ownerships came out right.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root mount "$container"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ mount="$output"
+
+ uid=$(stat -c %u ${mount})
+ gid=$(stat -c %g ${mount})
+ test ${uid}:${gid} = ${uidrange[$i]}:${gidrange[$i]}
+
+ for j in $(seq $n) ; do
+ ownerids=$(stat -c %u:%g ${mount}/file$j)
+ echo on-disk IDs: "$ownerids"
+ echo expected IDs: $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j))
+ [ "$ownerids" = $((${uidrange[$i]}+$j)):$((${gidrange[$i]}+$j)) ]
+ done
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root unmount "$container"
+ [ "$status" -eq 0 ]
+ done
+ # Each of the containers' layers should have the same parent layer,
+ # which should be the lone top layer for the image. The containers
+ # themselves have no contents at this point.
+ declare -a parents
+ echo containers list is \"${containers[*]}\"
+ for container in "${containers[@]}" ; do
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root container $container
+ echo container "$container":"$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ baseimage=$(grep ^Image: <<< "$output" | sed 's,^Image: ,,g')
+ echo baseimage:"$baseimage"
+ [ "$baseimage" = "$image" ]
+ layer=$(grep ^Layer: <<< "$output" | sed 's,^Layer: ,,g')
+ echo layer:"$layer"
+ size=$(grep ^Size: <<< "$output" | sed 's,^Size: ,,g')
+ [ "$size" -eq 0 ]
+ echo size:$size
+
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layer $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ parent=$(grep ^Parent: <<< "$output" | sed 's,^Parent: ,,g')
+ echo parent:"$parent"
+
+ parents[${#parents[*]}]="$parent"
+
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root image $baseimage
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ grep "^Top Layer: $parent" <<< "$output"
+ done
+ nparents=$(for p in ${parents[@]} ; do echo $p ; done | sort -u | wc -l)
+ echo nparents:$nparents
+ [ $nparents -eq 1 ]
+
+ # The image should still have only one top layer at this point.
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ tops=$(grep '^Top Layer:' <<< "$output" | sed 's,^Top Layer: ,,g')
+ ntops=$(for p in $tops; do echo $p ; done | sort -u | wc -l)
+ echo ntops:$ntops
+ [ $ntops -eq 1 ]
+
+ # Remove the containers and image and check that all of the layers we used got removed.
+ for container in "${containers[@]}" ; do
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root delete-container $container
+ done
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot delete-image $image
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+ run storage --debug=false --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layers
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" == "" ]
+}
+
+@test "idmaps-create-mapped-container-shifting" {
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ overlay*)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+
+ # Create a base layer.
+ run storage --debug=false create-layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ baselayer="$output"
+ # Create the lower layer.
+ run storage --debug=false create-layer $baselayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer.
+ run storage --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Put a file in the layer.
+ createrandom "$lowermount"/file
+ storage unmount $lowerlayer
+
+ imagename=idmappedimage-shifting
+ storage create-image --name=$imagename $lowerlayer
+}
+
+@test "idmaps-create-layer-from-another-image-store" {
+ # This test needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ if [ "$OS" != "Linux" ]; then
+ skip "not supported on $OS"
+ fi
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip ".imagestore option not supported by driver ${STORAGE_DRIVER}"
+ ;;
+ esac
+ case "$STORAGE_OPTION" in
+ *mount_program*)
+ skip "test not supported when using mount_program"
+ ;;
+ esac
+
+ n=5
+ host=2
+ # Create some temporary files.
+ for i in $(seq $n) ; do
+ createrandom "$TESTDIR"/file$i
+ chown ${i}:${i} "$TESTDIR"/file$i
+ ln -s . $TESTDIR/subdir$i
+ done
+ # Use them to create some diffs.
+ pushd $TESTDIR > /dev/null
+ for i in $(seq $n) ; do
+ tar cf diff${i}.tar subdir$i/
+ done
+ popd > /dev/null
+
+ # Create a layer using the host's mappings.
+ run storage --graph=$TESTDIR/imagestore --debug=false create-layer --hostuidmap --hostgidmap
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer="$output"
+
+ run storage --graph=$TESTDIR/imagestore --debug=false create-image $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+
+ run storage --graph=$TESTDIR/newstore --storage-opt=.imagestore=$TESTDIR/imagestore --debug=false create-image $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ image="$output"
+
+ for i in 0 $(seq $n) ; do
+ uidrange[$i]=$((($RANDOM+32767)*65536))
+ gidrange[$i]=$((($RANDOM+32767)*65536))
+ done
+
+ run storage --graph=$TESTDIR/newstore --storage-opt=.imagestore=$TESTDIR/imagestore --debug=false create-container --uidmap 0:${uidrange[0]}:$(($n+1)) --gidmap 0:${gidrange[0]}:$(($n+1)) $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+
+ storage --graph ${TESTDIR}/imagestore shutdown
+ storage --graph ${TESTDIR}/newstore shutdown
+}
diff --git a/tests/image-by-digest.bats b/tests/image-by-digest.bats
new file mode 100644
index 0000000..465aa9e
--- /dev/null
+++ b/tests/image-by-digest.bats
@@ -0,0 +1,113 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "images-by-digest" {
+ # Bail if "sha256sum" isn't available.
+ if test -z "$(which sha256sum 2> /dev/null)" ; then
+ skip "need sha256sum"
+ fi
+
+ # Create a couple of random files.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ createrandom ${TESTDIR}/random3
+ digest1=$(sha256sum ${TESTDIR}/random1)
+ digest2=$(sha256sum ${TESTDIR}/random2)
+ digest3=$(sha256sum ${TESTDIR}/random3)
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image using that layer.
+ run storage --debug=false create-image $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ firstimage=${output%% *}
+ # Set the first file as the manifest of this image.
+ run storage --debug=false set-image-data -f ${TESTDIR}/random1 ${firstimage} manifest
+ echo "$output"
+
+ # Create another image using that layer.
+ run storage --debug=false create-image $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ secondimage=${output%% *}
+ # Set the first file as the manifest of this image.
+ run storage --debug=false set-image-data -f ${TESTDIR}/random1 ${secondimage} manifest
+ echo "$output"
+
+ # Create yet another image using that layer.
+ run storage --debug=false create-image $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ thirdimage=${output%% *}
+ # Set the second file as the manifest of this image.
+ run storage --debug=false set-image-data -f ${TESTDIR}/random2 ${thirdimage} manifest
+ echo "$output"
+
+ # Create still another image using that layer.
+ run storage --debug=false create-image --digest sha256:${digest3// *} $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ fourthimage=${output%% *}
+
+ # Create another image using that layer.
+ run storage --debug=false create-image --digest sha256:${digest3// *} $layer
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ fifthimage=${output%% *}
+ # Set the third file as the manifest of this image.
+ run storage --debug=false set-image-data -f ${TESTDIR}/random3 ${fifthimage} manifest
+ echo "$output"
+
+ # Check that "images-by-digest" lists the right images.
+ run storage --debug=false images-by-digest --quiet sha256:${digest1// *}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 2 ]
+ [ "${lines[0]}" != "${lines[1]}" ]
+ [ "${lines[0]}" = "$firstimage" ] || [ "${lines[0]}" = "$secondimage" ]
+ [ "${lines[1]}" = "$firstimage" ] || [ "${lines[1]}" = "$secondimage" ]
+
+ run storage --debug=false images-by-digest --quiet sha256:${digest2// *}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 1 ]
+ [ "${lines[0]}" = "$thirdimage" ]
+
+ run storage --debug=false images-by-digest --quiet sha256:${digest3// *}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 2 ]
+ [ "${lines[0]}" = "$fourthimage" ] || [ "${lines[0]}" = "$fifthimage" ]
+ [ "${lines[1]}" = "$fourthimage" ] || [ "${lines[1]}" = "$fifthimage" ]
+
+ run storage --debug=false delete-image ${secondimage}
+ echo "$output"
+ [ "$status" -eq 0 ]
+
+ run storage --debug=false images-by-digest --quiet sha256:${digest1// *}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "${#lines[*]}" -eq 1 ]
+ [ "${lines[0]}" = "$firstimage" ]
+
+ run storage --debug=false delete-image ${firstimage}
+ echo "$output"
+ [ "$status" -eq 0 ]
+
+ run storage --debug=false images-by-digest --quiet sha256:${digest1// *}
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" = "" ]
+}
diff --git a/tests/image.bats b/tests/image.bats
new file mode 100644
index 0000000..d38607f
--- /dev/null
+++ b/tests/image.bats
@@ -0,0 +1,56 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "image" {
+ # Create and populate three interesting layers.
+ populate
+
+ # Create an image using to top layer.
+ name=wonderful-image
+ run storage --debug=false create-image --name $name $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${lines[0]}
+
+ # Add a couple of big data items.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ storage set-image-data -f ${TESTDIR}/random1 $image random1
+ storage set-image-data -f ${TESTDIR}/random2 $image random2
+
+ # Get information about the image, and make sure the ID, name, and data names were preserved.
+ run storage image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "ID: $image" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Data: random1" ]]
+ [[ "$output" =~ "Data: random2" ]]
+}
+
+@test "layerless-image" {
+ # Add an image with no specified layers.
+ name=wonderful-image
+ run storage --debug=false create-image --name $name
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${lines[0]}
+
+ # Add a couple of big data items.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ storage set-image-data -f ${TESTDIR}/random1 $image random1
+ storage set-image-data -f ${TESTDIR}/random2 $image random2
+
+ # Get information about the image, and make sure the ID, name, and data names were preserved,
+ # and that we can properly report its disk usage.
+ run storage image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "ID: $image" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Data: random1" ]]
+ [[ "$output" =~ "Data: random2" ]]
+ [[ "$output" =~ "Size: 512" ]]
+}
diff --git a/tests/import-layer.bats b/tests/import-layer.bats
new file mode 100644
index 0000000..ee33e38
--- /dev/null
+++ b/tests/import-layer.bats
@@ -0,0 +1,136 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "import-layer" {
+ # The checkdiffs function needs "tar".
+ if test -z "$(which tar 2> /dev/null)" ; then
+ skip "need tar"
+ fi
+
+ # Create and populate three interesting layers.
+ populate
+
+ # Extract the layers.
+ storage diff -u -f $TESTDIR/lower.tar $lowerlayer
+ storage diff -c -f $TESTDIR/middle.tar $midlayer
+ storage diff -u -f $TESTDIR/upper.tar $upperlayer
+
+ # Delete the layers.
+ storage delete-layer $upperlayer
+ storage delete-layer $midlayer
+ storage delete-layer $lowerlayer
+
+ # Import new layers using the layer diffs.
+ run storage --debug=false import-layer -f $TESTDIR/lower.tar
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+
+ run storage --debug=false import-layer -f $TESTDIR/middle.tar "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midlayer="$output"
+
+ run storage --debug=false import-layer -f $TESTDIR/upper.tar "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+
+ # The contents of these new layers should match what the old ones had.
+ checkchanges
+ checkdiffs
+}
+
+set_immutable() {
+ chflags schg $1
+}
+
+reset_immutable() {
+ chflags noschg $1
+}
+
+is_immutable() {
+ local flags=$(stat -f %#Xf $1)
+ [ "$((($flags & 0x20000) == 0x20000))" -ne 0 ]
+}
+
+@test "import-layer-with-immutable" {
+ if [ "$OS" != "FreeBSD" ]; then
+ skip "not supported on $OS"
+ fi
+
+ # Create a layer with a directory containing two files, both
+ # immutable. The directory is also set as immutablr.
+ run storage --debug=false create-layer
+ echo $output
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ run storage --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ local m="$output"
+ mkdir $m/dir
+ createrandom $m/dir/layer1file1
+ createrandom $m/dir/layer1file2
+ set_immutable $m/dir/layer1file1
+ set_immutable $m/dir/layer1file2
+ set_immutable $m/dir
+ storage unmount $lowerlayer
+
+ # Create a second layer which deletes one file and removes immutable from the other
+ run storage --debug=false create-layer "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ run storage --debug=false mount $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ m="$output"
+ reset_immutable $m/dir
+ reset_immutable $m/dir/layer1file1
+ rm $m/dir/layer1file1
+ reset_immutable $m/dir/layer1file2
+ set_immutable $m/dir
+ storage unmount $upperlayer
+
+ # Extract the layers.
+ storage diff -u -f $TESTDIR/lower.tar $lowerlayer
+ storage diff -u -f $TESTDIR/upper.tar $upperlayer
+
+ # Delete the layers.
+ storage delete-layer $upperlayer
+ storage delete-layer $lowerlayer
+
+ # Import new layers using the layer diffs.
+ run storage --debug=false import-layer -f $TESTDIR/lower.tar
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+
+ run storage --debug=false import-layer -f $TESTDIR/upper.tar "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+
+ # Verify layer contents
+ run storage --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ m="$output"
+ is_immutable $m/dir/layer1file1
+ is_immutable $m/dir/layer1file2
+ storage unmount $lowerlayer
+
+ run storage --debug=false mount $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ m="$output"
+ [ ! -f $m/dir/layer1file1 ]
+ ! is_immutable $m/dir/layer1file2
+ storage unmount $upperlayer
+
+ storage delete-layer $upperlayer
+ storage delete-layer $lowerlayer
+}
diff --git a/tests/layers.bats b/tests/layers.bats
new file mode 100644
index 0000000..80ec896
--- /dev/null
+++ b/tests/layers.bats
@@ -0,0 +1,58 @@
+#!/usr/bin/env bats
+# vim:set syn=bash:
+
+load helpers
+
+@test "allow storing images with more than 127 layers" {
+ LAYER=""
+ LIMIT=300
+ for i in $(seq 0 ${LIMIT}); do
+ echo "Layer: $i"
+
+ # Create a layer.
+ run storage --debug=false create-layer "$LAYER"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ LAYER="$output"
+ run storage --debug=false mount "$LAYER"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ ROOTFS="$output"
+ touch "${ROOTFS}"/$i
+ run storage --debug=false unmount "$LAYER"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ done
+
+ # Create the image
+ run storage --debug=false create-image "$LAYER"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ IMAGE="$output"
+
+ # Make sure the image has all of the content.
+ run storage --debug=false create-container "$IMAGE"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ CONTAINER="$output"
+
+ run storage --debug=false mount "$CONTAINER"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ ROOTFS="$output"
+ for i in $(seq 0 ${LIMIT}); do
+ if ! test -r "${ROOTFS}"/$i ; then
+ echo File from layer $i of ${LIMIT} was not visible after mounting
+ false
+ fi
+ done
+
+ run storage --debug=false unmount "$CONTAINER"
+ echo "$output"
+ [ "$status" -eq 0 ]
+}
diff --git a/tests/manifests.bats b/tests/manifests.bats
new file mode 100644
index 0000000..1985d1f
--- /dev/null
+++ b/tests/manifests.bats
@@ -0,0 +1,67 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "manifests" {
+ # Create and populate three interesting layers.
+ populate
+
+ # Create an image using the top layer.
+ name=wonderful-image
+ run storage --debug=false create-image --name $name $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${lines[0]}
+
+ # Add a couple of big data items as manifests.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ createrandom ${TESTDIR}/random3
+ digest1=$(sha256sum ${TESTDIR}/random1)
+ digest1=${digest1// *}
+ digest2=$(sha256sum ${TESTDIR}/random2)
+ digest2=${digest2// *}
+ digest3=$(sha256sum ${TESTDIR}/random3)
+ digest3=${digest3// *}
+ storage set-image-data -f ${TESTDIR}/random1 $image manifest
+ storage set-image-data -f ${TESTDIR}/random2 $image manifest-random2
+ storage set-image-data -f ${TESTDIR}/random3 $image manifest-random3
+ storage add-names --name localhost/fooimage:latest $image
+
+ # Get information about the image, and make sure the ID, name, and data names were preserved.
+ run storage image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "ID: $image" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Digest: sha256:$digest1" ]]
+ [[ "$output" =~ "Digest: sha256:$digest2" ]]
+ [[ "$output" =~ "Digest: sha256:$digest3" ]]
+
+ run storage images-by-digest sha256:$digest1
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "$image" ]]
+ [[ "$output" =~ "name: $name" ]]
+ [[ "$output" =~ "digest: sha256:$digest1" ]]
+ [[ "$output" =~ "digest: sha256:$digest2" ]]
+ [[ "$output" =~ "digest: sha256:$digest3" ]]
+
+ run storage images-by-digest sha256:$digest2
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "$image" ]]
+ [[ "$output" =~ "name: $name" ]]
+ [[ "$output" =~ "digest: sha256:$digest1" ]]
+ [[ "$output" =~ "digest: sha256:$digest2" ]]
+ [[ "$output" =~ "digest: sha256:$digest3" ]]
+
+ run storage images-by-digest sha256:$digest3
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "$image" ]]
+ [[ "$output" =~ "name: $name" ]]
+ [[ "$output" =~ "digest: sha256:$digest1" ]]
+ [[ "$output" =~ "digest: sha256:$digest2" ]]
+ [[ "$output" =~ "digest: sha256:$digest3" ]]
+}
diff --git a/tests/metadata.bats b/tests/metadata.bats
new file mode 100644
index 0000000..eb2aabd
--- /dev/null
+++ b/tests/metadata.bats
@@ -0,0 +1,137 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "metadata" {
+ echo danger > $TESTDIR/danger.txt
+
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Make sure the layer's there.
+ storage exists -l $layer
+
+ # Create an image using the layer and directly-supplied metadata.
+ run storage --debug=false create-image -m danger $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Make sure that the image is there.
+ storage exists -i $image
+
+ # Read back the metadata and make sure it's the right value.
+ run storage --debug=false metadata -q $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Change the metadata to a directly-supplied value.
+ run storage set-metadata -m thunder $image
+ [ "$status" -eq 0 ]
+
+ # Read back the metadata and make sure it's the new value.
+ run storage --debug=false metadata -q $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "thunder" ]
+
+ # Change the metadata to a value supplied via a file.
+ storage set-metadata -f $TESTDIR/danger.txt $image
+
+ # Read back the metadata and make sure it's the newer value.
+ run storage --debug=false metadata -q $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Create an image using the layer and metadata read from a file.
+ run storage --debug=false create-image -f $TESTDIR/danger.txt $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Make sure that the image is there.
+ storage exists -i $image
+
+ # Read back the metadata and make sure it's the right value.
+ run storage --debug=false metadata -q $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Change the metadata to a directly-supplied value.
+ storage set-metadata -m thunder $image
+
+ # Read back the metadata and make sure it's the new value.
+ run storage --debug=false metadata -q $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "thunder" ]
+
+ # Change the metadata to a value supplied via a file.
+ storage set-metadata -f $TESTDIR/danger.txt $image
+
+ # Read back the metadata and make sure it's the newer value.
+ run storage --debug=false metadata -q $image
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Create a container based on the image and directly-supplied metadata.
+ run storage --debug=false create-container -m danger $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Make sure the container is there.
+ storage exists -c $container
+
+ # Read the metadata and make sure it's the right value.
+ run storage --debug=false metadata -q $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Change the metadata to a new value.
+ storage set-metadata -m thunder $container
+
+ # Read back the new metadata value.
+ run storage --debug=false metadata -q $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "thunder" ]
+
+ # Change the metadata to a new value read from a file.
+ storage set-metadata -f $TESTDIR/danger.txt $container
+
+ # Read back the newer metadata value.
+ run storage --debug=false metadata -q $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Create a container based on the image and metadata read from a file.
+ run storage --debug=false create-container -f $TESTDIR/danger.txt $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Make sure the container is there.
+ storage exists -c $container
+
+ # Read the metadata and make sure it's the right value.
+ run storage --debug=false metadata -q $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+
+ # Change the metadata to a new value.
+ storage set-metadata -m thunder $container
+
+ # Read back the new metadata value.
+ run storage --debug=false metadata -q $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "thunder" ]
+
+ # Change the metadata to a new value read from a file.
+ storage set-metadata -f $TESTDIR/danger.txt $container
+
+ # Read back the newer metadata value.
+ run storage --debug=false metadata -q $container
+ [ "$status" -eq 0 ]
+ [ "$output" = "danger" ]
+}
diff --git a/tests/mount-layer.bats b/tests/mount-layer.bats
new file mode 100644
index 0000000..2508436
--- /dev/null
+++ b/tests/mount-layer.bats
@@ -0,0 +1,85 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "mount-layer" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer="$output"
+
+ # Mount the layer.
+ run storage --debug=false mount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Check if layer is mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "$layer mounted" ]
+ # Unmount the layer.
+ run storage --debug=false unmount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Make sure layer is not mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "" ]
+
+ # Mount the layer twice.
+ run storage --debug=false mount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ run storage --debug=false mount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Check if layer is mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "$layer mounted" ]
+ # Unmount the second layer.
+ run storage --debug=false unmount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "" ]
+ # Check if layer is mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "$layer mounted" ]
+ # Unmount the first layer.
+ run storage --debug=false unmount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Make sure layer is not mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "" ]
+
+
+ # Mount the layer twice and force umount.
+ run storage --debug=false mount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ run storage --debug=false mount $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Check if layer is mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "$layer mounted" ]
+ # Unmount all layers.
+ run storage --debug=false unmount --force $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Make sure no layers are mounted.
+ run storage --debug=false mounted $layer
+ [ "$status" -eq 0 ]
+ [ "$output" == "" ]
+
+ # Mount the layer with nosuid
+ run storage --debug=false mount --option nosuid $layer
+ [ "$status" -ne 0 ]
+
+ # Delete the first layer
+ run storage delete-layer $layer
+ [ "$status" -eq 0 ]
+}
diff --git a/tests/names.bats b/tests/names.bats
new file mode 100644
index 0000000..0d8779f
--- /dev/null
+++ b/tests/names.bats
@@ -0,0 +1,722 @@
+#!/usr/bin/env bats
+
+load helpers
+
+# Helper function to scan the list of names of an item for a particular value.
+check-for-name() {
+ name="$1"
+ shift
+ run storage --debug=false get-names "$@"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "$name" ]]
+}
+
+@test "names at creation: layers" {
+ # Create a layer with no name.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer=$output
+
+ # Verify that the layer exists and can be found by ID.
+ run storage exists -l $lowerlayer
+ [ "$status" -eq 0 ]
+ # Verify that these three names don't appear to be assigned.
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -ne 0 ]
+ run storage exists -l barlayer
+ [ "$status" -ne 0 ]
+
+ # Create a new layer and give it two of the above-mentioned names.
+ run storage --debug=false create-layer -n foolayer -n barlayer $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer=${output%% *}
+
+ # Verify that the new layer exists and can be found by its ID.
+ run storage exists -l $upperlayer
+ [ "$status" -eq 0 ]
+ # Verify that two of the names we checked earlier are now assigned, and to the new layer.
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -eq 0 ]
+ run storage exists -l barlayer
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $upperlayer
+ [ "$status" -ne 0 ]
+ run check-for-name foolayer $upperlayer
+ [ "$status" -eq 0 ]
+ run check-for-name barlayer $upperlayer
+ [ "$status" -eq 0 ]
+}
+
+@test "add-names: layers" {
+ # Create a layer with no name.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer=$output
+
+ # Verify that we can find the layer by its ID.
+ run storage exists -l $lowerlayer
+ [ "$status" -eq 0 ]
+
+ # Check that these three names are not currently assigned.
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -ne 0 ]
+ run storage exists -l barlayer
+ [ "$status" -ne 0 ]
+
+ # Create a new layer with names.
+ run storage --debug=false create-layer -n foolayer -n barlayer $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer=${output%% *}
+
+ # Add names to the new layer.
+ run storage add-names -n newlayer -n otherlayer $upperlayer
+ [ "$status" -eq 0 ]
+
+ # Verify that we can find the new layer by its ID.
+ run storage exists -l $upperlayer
+ [ "$status" -eq 0 ]
+ # Verify that the name we didn't assign is still unassigned, and that the two names we
+ # started with, along with the two we added, are assigned, to the new layer.
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -eq 0 ]
+ run storage exists -l barlayer
+ [ "$status" -eq 0 ]
+ run storage exists -l newlayer
+ [ "$status" -eq 0 ]
+ run storage exists -l otherlayer
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $upperlayer
+ [ "$status" -ne 0 ]
+ run check-for-name foolayer $upperlayer
+ [ "$status" -eq 0 ]
+ run check-for-name barlayer $upperlayer
+ [ "$status" -eq 0 ]
+ run check-for-name newlayer $upperlayer
+ [ "$status" -eq 0 ]
+ run check-for-name otherlayer $upperlayer
+ [ "$status" -eq 0 ]
+}
+
+@test "set-names: layers" {
+ # Create a layer with no name.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer=$output
+
+ # Verify that we can find the layer by its ID.
+ run storage exists -l $lowerlayer
+ [ "$status" -eq 0 ]
+
+ # Check that these three names are not currently assigned.
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -ne 0 ]
+ run storage exists -l barlayer
+ [ "$status" -ne 0 ]
+
+ # Create a new layer with two names.
+ run storage --debug=false create-layer -n foolayer -n barlayer $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer=${output%% *}
+
+ # Assign a list of two names to the layer, which should remove its other names.
+ run storage set-names -n newlayer -n otherlayer $upperlayer
+ [ "$status" -eq 0 ]
+
+ # Check that the old names are not assigned at all, but the new names are, to it.
+ run storage exists -l $upperlayer
+ [ "$status" -eq 0 ]
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -ne 0 ]
+ run storage exists -l barlayer
+ [ "$status" -ne 0 ]
+ run storage exists -l newlayer
+ [ "$status" -eq 0 ]
+ run storage exists -l otherlayer
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $upperlayer
+ [ "$status" -ne 0 ]
+ run check-for-name foolayer $upperlayer
+ [ "$status" -ne 0 ]
+ run check-for-name barlayer $upperlayer
+ [ "$status" -ne 0 ]
+ run check-for-name newlayer $upperlayer
+ [ "$status" -eq 0 ]
+ run check-for-name otherlayer $upperlayer
+ [ "$status" -eq 0 ]
+}
+
+@test "move-names: layers" {
+ # Create a layer with no name.
+ run storage --debug=false create-layer -n foolayer -n barlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer=${output%% *}
+
+ # Verify that we can find the layer by its ID.
+ run storage exists -l $lowerlayer
+ [ "$status" -eq 0 ]
+
+ # Check that these three names are not currently assigned.
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -eq 0 ]
+ run storage exists -l barlayer
+ [ "$status" -eq 0 ]
+
+ # Create another layer with no names.
+ run storage --debug=false create-layer $lowerlayer
+ [ "$status" -eq 0 ]
+ upperlayer=${output%% *}
+
+ # Set names on that new layer, which should remove the names from the old one.
+ run storage set-names -n foolayer -n barlayer $upperlayer
+ [ "$status" -eq 0 ]
+
+ # Verify that we can find the layer by its ID, and that the two names exist.
+ run storage exists -l $upperlayer
+ [ "$status" -eq 0 ]
+ run storage exists -l no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -l foolayer
+ [ "$status" -eq 0 ]
+ run storage exists -l barlayer
+ [ "$status" -eq 0 ]
+
+ # Check that the names are attached to the new layer and not the old one.
+ run check-for-name foolayer $lowerlayer
+ [ "$status" -ne 0 ]
+ run check-for-name barlayer $lowerlayer
+ [ "$status" -ne 0 ]
+ run check-for-name foolayer $upperlayer
+ [ "$status" -eq 0 ]
+ run check-for-name barlayer $upperlayer
+ [ "$status" -eq 0 ]
+}
+
+@test "names at creation: images" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image with names that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Check that we can find that image by ID and by its names.
+ run storage exists -i $image
+ [ "$status" -eq 0 ]
+ run storage exists -i no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage exists -i barimage
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $image
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name barimage $image
+ [ "$status" -eq 0 ]
+}
+
+@test "add-names: images" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image with names that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Check that we can find that image by ID and by its names.
+ run storage exists -i $image
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $image
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name barimage $image
+ [ "$status" -eq 0 ]
+
+ # Add two names to the image.
+ run storage add-names -n newimage -n otherimage $image
+ [ "$status" -eq 0 ]
+
+ # Check that all of the names are now assigned.
+ run storage exists -i no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage exists -i barimage
+ [ "$status" -eq 0 ]
+ run storage exists -i newimage
+ [ "$status" -eq 0 ]
+ run storage exists -i otherimage
+ [ "$status" -eq 0 ]
+
+ # Check that all of the names are now assigned to this image.
+ run check-for-name no-such-thing-as-this-name $image
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name barimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name newimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name otherimage $image
+ [ "$status" -eq 0 ]
+}
+
+@test "set-names: images" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image with names that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Check that we can find that image by ID and by its names.
+ run storage exists -i $image
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $image
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name barimage $image
+ [ "$status" -eq 0 ]
+
+ # Set the names for the image to two new names.
+ run storage set-names -n newimage -n otherimage $image
+ [ "$status" -eq 0 ]
+
+ # Check that the two new names are the only ones assigned.
+ run storage exists -i no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -i fooimage
+ [ "$status" -ne 0 ]
+ run storage exists -i barimage
+ [ "$status" -ne 0 ]
+ run storage exists -i newimage
+ [ "$status" -eq 0 ]
+ run storage exists -i otherimage
+ [ "$status" -eq 0 ]
+
+ # Check that the two new names are the only ones on this image.
+ run check-for-name no-such-thing-as-this-name $image
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $image
+ [ "$status" -ne 0 ]
+ run check-for-name barimage $image
+ [ "$status" -ne 0 ]
+ run check-for-name newimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name otherimage $image
+ [ "$status" -eq 0 ]
+}
+
+@test "move-names: images" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image with names that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ firstimage=${output%% *}
+
+ # Create another image with no names.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Check that we can find the first image by ID and by its names.
+ run storage exists -i $firstimage
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $firstimage
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $firstimage
+ [ "$status" -eq 0 ]
+ run check-for-name barimage $firstimage
+ [ "$status" -eq 0 ]
+
+ # Set a name list on the new image that includes the names of the old one.
+ run storage set-names -n fooimage -n barimage -n newimage -n otherimage $image
+ [ "$status" -eq 0 ]
+
+ # Check that all of the names are assigned.
+ run storage exists -i no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage exists -i barimage
+ [ "$status" -eq 0 ]
+ run storage exists -i newimage
+ [ "$status" -eq 0 ]
+ run storage exists -i otherimage
+ [ "$status" -eq 0 ]
+
+ # Check that all of the names are assigned to the new image.
+ run check-for-name no-such-thing-as-this-name $image
+ [ "$status" -ne 0 ]
+ run check-for-name fooimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name barimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name newimage $image
+ [ "$status" -eq 0 ]
+ run check-for-name otherimage $image
+ [ "$status" -eq 0 ]
+}
+
+@test "add-names: ro-images" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+
+ # Create a layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image with names that uses that layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Check that we can find the image by ID and by its names.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i $image
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i barimage
+ [ "$status" -eq 0 ]
+
+ # Add a pair of names to the image.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root add-names -n newimage -n otherimage $image
+ echo "add-names:" "$output"
+ [ "$status" -eq 0 ]
+
+ # Check that all of the names are resolveable.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root images
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i $image
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i barimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i newimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i otherimage
+ [ "$status" -eq 0 ]
+}
+
+@test "remove-names: ro-images" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+
+ mkdir ${TESTDIR}/{ro-root,ro-runroot}
+
+ # Create a layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image with names that uses that layer.
+ run storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot create-image -n fooimage -n barimage -n newimage -n otherimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ storage --debug=false --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Check that we can find the image by ID and by its names.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i $image
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i barimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i newimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i otherimage
+ [ "$status" -eq 0 ]
+
+ # Remove one of the names from the image.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root remove-names -n newimage $image
+ echo "remove-names:" "$output"
+ [ "$status" -eq 0 ]
+
+ # Check that all of the names are still resolveable, except for the one we removed.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i $image
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i fooimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i barimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i newimage
+ [ "$status" -ne 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root exists -i otherimage
+ [ "$status" -eq 0 ]
+}
+
+@test "names at creation: containers" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image that uses that layer.
+ run storage --debug=false create-image $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container with two names, based on that image.
+ run storage --debug=false create-container -n foocontainer -n barcontainer $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that we can find the container using either its ID or names.
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run storage exists -c no-such-thing-as-this-name
+ [ "$status" -ne 0 ]
+ run storage exists -c foocontainer
+ [ "$status" -eq 0 ]
+ run storage exists -c barcontainer
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $container
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -eq 0 ]
+}
+
+@test "add-names: containers" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container with two names, based on that image.
+ run storage --debug=false create-container -n foocontainer -n barcontainer $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that we can find the container using either its ID or names.
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $container
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -eq 0 ]
+
+ # Add two names to the container.
+ run storage add-names -n newcontainer -n othercontainer $container
+ [ "$status" -eq 0 ]
+
+ # Verify that all of those names are assigned to the container.
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $container
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name newcontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name othercontainer $container
+ [ "$status" -eq 0 ]
+}
+
+@test "set-names: containers" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container with two names, based on that image.
+ run storage --debug=false create-container -n foocontainer -n barcontainer $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that we can find the container using either its ID or names.
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $container
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -eq 0 ]
+
+ # Set the list of names for the container to just these two values.
+ run storage set-names -n newcontainer -n othercontainer $container
+ [ "$status" -eq 0 ]
+
+ # Check that these are the only two names attached to the container.
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $container
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -ne 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -ne 0 ]
+ run check-for-name newcontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name othercontainer $container
+ [ "$status" -eq 0 ]
+}
+
+@test "move-names: containers" {
+ # Create a layer.
+ run storage --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ layer=$output
+
+ # Create an image that uses that layer.
+ run storage --debug=false create-image -n fooimage -n barimage $layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${output%% *}
+
+ # Create a container with two names, based on that image.
+ run storage --debug=false create-container -n foocontainer -n barcontainer $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ firstcontainer=${output%% *}
+
+ # Create another container with two different names, based on that image.
+ run storage --debug=false create-container -n newcontainer -n othercontainer $image
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container=${output%% *}
+
+ # Check that we can access both containers by ID, and that they have the right names.
+ run storage exists -c $firstcontainer
+ [ "$status" -eq 0 ]
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $firstcontainer
+ [ "$status" -eq 0 ]
+ run check-for-name barcontainer $firstcontainer
+ [ "$status" -eq 0 ]
+ run check-for-name newcontainer $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name othercontainer $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -ne 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -ne 0 ]
+ run check-for-name newcontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name othercontainer $container
+ [ "$status" -eq 0 ]
+
+ # Set the names on the new container to the names we gave the old one.
+ run storage set-names -n foocontainer -n barcontainer $container
+ [ "$status" -eq 0 ]
+
+ # Check that the containers can still be found, and that the names are correctly set.
+ run storage exists -c $firstcontainer
+ [ "$status" -eq 0 ]
+ run storage exists -c $container
+ [ "$status" -eq 0 ]
+ run check-for-name no-such-thing-as-this-name $container
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name barcontainer $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name newcontainer $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name othercontainer $firstcontainer
+ [ "$status" -ne 0 ]
+ run check-for-name foocontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name barcontainer $container
+ [ "$status" -eq 0 ]
+ run check-for-name newcontainer $container
+ [ "$status" -ne 0 ]
+ run check-for-name othercontainer $container
+ [ "$status" -ne 0 ]
+}
diff --git a/tests/overlay-recreate.bats b/tests/overlay-recreate.bats
new file mode 100644
index 0000000..038a488
--- /dev/null
+++ b/tests/overlay-recreate.bats
@@ -0,0 +1,33 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "overlay-recreate" {
+ case "$STORAGE_DRIVER" in
+ overlay)
+ ;;
+ *)
+ skip "not applicable to driver $STORAGE_DRIVER"
+ ;;
+ esac
+ populate
+ # behold my destructive power!
+ rm -v ${TESTDIR}/root/overlay/l/*
+ # we should be able to recover from that.
+ storage mount "$lowerlayer"
+ storage unmount "$lowerlayer"
+ storage mount "$midlayer"
+ storage unmount "$midlayer"
+ storage mount "$upperlayer"
+ storage unmount "$upperlayer"
+ # okay, but how about this?
+ rm -v ${TESTDIR}/root/overlay/*/link
+ # yeah, we can handle that, too.
+ storage mount "$lowerlayer"
+ storage unmount "$lowerlayer"
+ storage mount "$midlayer"
+ storage unmount "$midlayer"
+ storage mount "$upperlayer"
+ storage unmount "$upperlayer"
+ # okay, not bad, kid.
+}
diff --git a/tests/split-store.bats b/tests/split-store.bats
new file mode 100644
index 0000000..dbd69dd
--- /dev/null
+++ b/tests/split-store.bats
@@ -0,0 +1,109 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "split-store" {
+ # Create and populate three interesting layers.
+ populate
+
+ # Create an image using to top layer.
+ name=wonderful-image
+ run mkdir -p ${TESTDIR}/imagestore
+ run mkdir -p ${TESTDIR}/emptyimagestore
+ run storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ --debug=false create-image --name $name
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${lines[0]}
+
+ # Add a couple of big data items.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ set-image-data -f ${TESTDIR}/random1 $image random1
+ storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ set-image-data -f ${TESTDIR}/random2 $image random2
+
+ # Get information about the image, and make sure the ID, name, and data names were preserved.
+ run storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "ID: $image" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Data: random1" ]]
+ [[ "$output" =~ "Data: random2" ]]
+
+ # shutdown store
+ run storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ shutdown
+
+ # Similar data must not be shown when image-store is switched to empty store
+ run storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/emptyimagestore/ --run ${TESTDIR}/runroot/ image $image
+ echo "$output"
+ [[ "$output" != "ID: $image" ]]
+ [[ "$output" != "Name: $name" ]]
+ [[ "$output" != "Data: random1" ]]
+ [[ "$output" != "Data: random2" ]]
+
+ # shutdown store
+ run storage --graph ${TESTDIR}/graph/ --image-store ${TESTDIR}/emptyimagestore/ --run ${TESTDIR}/runroot/ shutdown
+}
+
+@test "split-store - use graphRoot as an additional store by default" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "additional store not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ # Create and populate three interesting layers.
+ populate
+
+ # Create an image using to top layer.
+ name=wonderful-image
+ run mkdir -p ${TESTDIR}/imagestore
+ run storage --graph ${TESTDIR}/graph --debug=false create-image --name $name
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ image=${lines[0]}
+
+ # Add a couple of big data items.
+ createrandom ${TESTDIR}/random1
+ createrandom ${TESTDIR}/random2
+ storage --graph ${TESTDIR}/graph set-image-data -f ${TESTDIR}/random1 $image random1
+ storage --graph ${TESTDIR}/graph set-image-data -f ${TESTDIR}/random2 $image random2
+
+ # Get information about the image, and make sure the ID, name, and data names were preserved.
+ run storage --graph ${TESTDIR}/graph image $image
+ echo "$output"
+ [ "$status" -eq 0 ]
+ [[ "$output" =~ "ID: $image" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Data: random1" ]]
+ [[ "$output" =~ "Data: random2" ]]
+
+ # shutdown store
+ run storage --graph ${TESTDIR}/graph shutdown
+
+ # Similar data must not be shown when image-store is switched to empty store
+ run storage --graph ${TESTDIR}/graph --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ image $image
+ echo "$output"
+ [[ "$output" =~ "ID: $image" ]]
+ [[ "$output" =~ "Name: $name" ]]
+ [[ "$output" =~ "Data: random1" ]]
+ [[ "$output" =~ "Data: random2" ]]
+
+ # shutdown store
+ run storage --graph ${TESTDIR}/graph --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ shutdown
+
+ # Even though image only exists on graphRoot, user must
+ # be able able to delete the image on graphRoot while `--image-store`
+ # is still set.
+ run storage --graph ${TESTDIR}/graph --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ delete-image $image
+ # shutdown store
+ run storage --graph ${TESTDIR}/graph --image-store ${TESTDIR}/imagestore/ --run ${TESTDIR}/runroot/ shutdown
+
+ # Now since image was deleted from graphRoot, we should
+ # get false output while checking if image still exists
+ run storage --graph ${TESTDIR}/graph exists -i $image
+ [ "$status" -ne 0 ]
+ # shutdown store
+ run storage --graph ${TESTDIR}/graph shutdown
+}
diff --git a/tests/status.bats b/tests/status.bats
new file mode 100644
index 0000000..30f7a4b
--- /dev/null
+++ b/tests/status.bats
@@ -0,0 +1,18 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "status" {
+ run storage --debug=false status
+ echo :"$output":
+ [ "$status" -eq 0 ]
+ # Expect the first line of the output to be the storage root directory location.
+ [ "${lines[0]/:*/}" = "Root" ]
+ [ "${lines[0]/*: /}" = "${TESTDIR}/root" ]
+ # Expect the second line of the output to be the storage runroot directory location.
+ [ "${lines[1]/:*/}" = "Run Root" ]
+ [ "${lines[1]/*: /}" = "${TESTDIR}/runroot" ]
+ # Expect the third line of the output to be "Driver Name: $STORAGE_DRIVER".
+ [ "${lines[2]/:*/}" = "Driver Name" ]
+ [ "${lines[2]/*: /}" = "$STORAGE_DRIVER" ]
+}
diff --git a/tests/stores.bats b/tests/stores.bats
new file mode 100644
index 0000000..dbe99e3
--- /dev/null
+++ b/tests/stores.bats
@@ -0,0 +1,153 @@
+#!/usr/bin/env bats
+
+load helpers
+
+@test "additional-stores" {
+ case "$STORAGE_DRIVER" in
+ overlay*|vfs)
+ ;;
+ *)
+ skip "not supported by driver $STORAGE_DRIVER"
+ ;;
+ esac
+ # Initialize a store somewhere that we'll later use as a read-only store.
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot layers
+ # Fail this test if we can't initialize the driver with the option.
+ storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layers
+ # Create a layer in what will become the read-only store.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerlayer="$output"
+ # Mount the layer in what will become the read-only store.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false mount $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowermount="$output"
+ # Put a file in the layer in what will become the read-only store.
+ createrandom "$lowermount"/layer1file1
+
+ # Create a second layer based on the first one in what will become the read-only store.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-layer "$lowerlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midlayer="$output"
+ # Mount that layer, too.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false mount $midlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ midmount="$output"
+ # Check that the file from the first layer is there.
+ test -s "$midmount"/layer1file1
+ # Check that we can remove it...
+ rm -f -v "$midmount"/layer1file1
+ # ... and that doing so doesn't affect the first layer.
+ test -s "$lowermount"/layer1file1
+ # Create a new file in this layer.
+ createrandom "$midmount"/layer2file1
+ # Unmount this layer.
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot unmount $midlayer
+ # Unmount the first layer.
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot unmount $lowerlayer
+
+ # Create an image using this second layer.
+ run storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot --debug=false create-image $midlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ lowerimage=${output%% *}
+
+ # We no longer need to use the read-only root as a writeable location, so shut it down.
+ storage --graph ${TESTDIR}/ro-root --run ${TESTDIR}/ro-runroot shutdown
+
+ # Create a third layer based on the second one.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false create-layer "$midlayer"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperlayer="$output"
+ # Mount this layer.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false mount $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppermount="$output"
+ # Check that the file we removed from the second layer is still gone.
+ run test -s "$uppermount"/layer1file1
+ [ "$status" -ne 0 ]
+ # Check that the file we added to the second layer is still there.
+ test -s "$uppermount"/layer2file1
+ # Unmount the third layer.
+ storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root unmount $upperlayer
+
+ # Create an image using this third layer.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false create-image $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ upperimage=${output%% *}
+ # Create a container based on the upperimage.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false create-container "$upperimage"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppercontainer="$output"
+ # Mount this container.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false mount $uppercontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ uppercontainermount="$output"
+ # Check that the file we removed from the second layer is still gone.
+ run test -s "$uppercontainermount"/layer1file1
+ [ "$status" -ne 0 ]
+ # Check that the file we added to the second layer is still there.
+ test -s "$uppercontainermount"/layer2file1
+ # Unmount the container.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false unmount $uppercontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ # Delete the container.
+ storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root delete-container $uppercontainer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root add-names -n newimage $lowerimage
+ [ "$status" -eq 0 ]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root delete-image newimage
+ [ "$status" -eq 0 ]
+
+ # Create a container based on the lowerimage.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false create-container "$lowerimage"
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ container="$output"
+ # Mount this container.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root --debug=false mount $container
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ containermount="$output"
+ # Check that the file we removed from the second layer is still gone.
+ run test -s "$containermount"/layer1file1
+ [ "$status" -ne 0 ]
+ # Check that the file we added to the second layer is still there.
+ test -s "$containermount"/layer2file1
+ # Unmount the container.
+ storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root delete-container $container
+
+ # Check that the first two layers and the first image are marked read-only, and that the rest are not.
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layer $lowerlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ [[ "$output" =~ "Read Only: true" ]]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layer $midlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ [[ "$output" =~ "Read Only: true" ]]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root layer $upperlayer
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ ! [[ "$output" =~ "Read Only: true" ]]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root image $lowerimage
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ [[ "$output" =~ "Read Only: true" ]]
+ run storage --storage-opt ${STORAGE_DRIVER}.imagestore=${TESTDIR}/ro-root image $upperimage
+ [ "$status" -eq 0 ]
+ [ "$output" != "" ]
+ ! [[ "$output" =~ "Read Only: true" ]]
+}
diff --git a/tests/test_drivers.bash b/tests/test_drivers.bash
new file mode 100755
index 0000000..f552260
--- /dev/null
+++ b/tests/test_drivers.bash
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+TMPDIR=${TMPDIR:-/var/tmp}
+
+aufs() {
+ modprobe aufs 2> /dev/null
+ grep -E -q ' aufs$' /proc/filesystems
+}
+
+btrfs() {
+ [ $(stat -f -c %T ${TMPDIR}) = btrfs ]
+}
+
+devicemapper() {
+ for binary in pvcreate vgcreate lvcreate lvconvert lvchange thin_check ; do
+ if ! which $binary > /dev/null 2> /dev/null ; then
+ return 1
+ fi
+ done
+ pkg-config devmapper 2> /dev/null
+}
+
+overlay() {
+ modprobe overlay 2> /dev/null
+ grep -E -q ' overlay$' /proc/filesystems
+}
+
+zfs() {
+ [ "$(stat -f -c %T ${TMPDIR:-/tmp})" = zfs ]
+}
+
+if [ "$STORAGE_DRIVER" = "" ] ; then
+ drivers=vfs
+ if aufs ; then
+ drivers="$drivers aufs"
+ fi
+ if btrfs; then
+ drivers="$drivers btrfs"
+ fi
+ if devicemapper; then
+ drivers="$drivers devicemapper"
+ fi
+ if overlay; then
+ drivers="$drivers overlay"
+ fi
+ if zfs; then
+ drivers="$drivers zfs"
+ fi
+else
+ drivers="$STORAGE_DRIVER"
+fi
+set -e
+for driver in $drivers ; do
+ echo '['STORAGE_DRIVER="$driver"']'
+ env STORAGE_DRIVER="$driver" $(dirname ${BASH_SOURCE})/test_runner.bash "$@"
+done
diff --git a/tests/test_runner.bash b/tests/test_runner.bash
new file mode 100755
index 0000000..868df60
--- /dev/null
+++ b/tests/test_runner.bash
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+set -e
+
+cd "$(dirname "$(readlink -f "$BASH_SOURCE")")"
+
+# Load the helpers.
+. helpers.bash
+
+function execute() {
+ >&2 echo "++ $@"
+ eval "$@"
+}
+
+# Tests to run. Defaults to all.
+TESTS=${@:-.}
+
+# Run the tests.
+execute time bats --tap $TESTS
diff --git a/tests/tools/Makefile b/tests/tools/Makefile
new file mode 100644
index 0000000..9cc9eed
--- /dev/null
+++ b/tests/tools/Makefile
@@ -0,0 +1,34 @@
+GO := go
+BUILDDIR := build
+
+all: $(BUILDDIR)
+
+.PHONY: vendor
+vendor:
+ $(GO) mod tidy
+ $(GO) mod vendor
+ $(GO) mod verify
+
+define go-build
+ $(shell cd `pwd` && $(GO) build -mod=vendor -o $(BUILDDIR)/$(shell basename $(1)) $(1))
+ @echo > /dev/null
+endef
+
+.PHONY: clean
+clean:
+ rm -rf $(BUILDDIR)
+
+$(BUILDDIR): \
+ $(BUILDDIR)/git-validation \
+ $(BUILDDIR)/go-md2man \
+ $(BUILDDIR)/golangci-lint
+
+$(BUILDDIR)/git-validation:
+ $(call go-build,./vendor/github.com/vbatts/git-validation)
+
+$(BUILDDIR)/go-md2man:
+ $(call go-build,./vendor/github.com/cpuguy83/go-md2man)
+
+$(BUILDDIR)/golangci-lint: VERSION=v1.51.2
+$(BUILDDIR)/golangci-lint:
+ curl -fsSL https://raw.githubusercontent.com/golangci/golangci-lint/$(VERSION)/install.sh | sh -s -- -b ./$(BUILDDIR) $(VERSION)
diff --git a/tests/tools/go.mod b/tests/tools/go.mod
new file mode 100644
index 0000000..6a5d78a
--- /dev/null
+++ b/tests/tools/go.mod
@@ -0,0 +1,16 @@
+module github.com/containers/storage/tests/tools
+
+go 1.18
+
+require (
+ github.com/cpuguy83/go-md2man v1.0.10
+ github.com/vbatts/git-validation v1.0.0
+)
+
+require (
+ github.com/hashicorp/go-version v1.2.0 // indirect
+ github.com/konsorten/go-windows-terminal-sequences v1.0.1 // indirect
+ github.com/russross/blackfriday v1.5.2 // indirect
+ github.com/sirupsen/logrus v1.4.1 // indirect
+ golang.org/x/sys v0.5.0 // indirect
+)
diff --git a/tests/tools/go.sum b/tests/tools/go.sum
new file mode 100644
index 0000000..09ec98b
--- /dev/null
+++ b/tests/tools/go.sum
@@ -0,0 +1,22 @@
+github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
+github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/vbatts/git-validation v1.0.0 h1:Eb7bD3ThOk/2P01M+KaUng0gka9+MVvpn6d0a6AKxq0=
+github.com/vbatts/git-validation v1.0.0/go.mod h1:QyK3uQnRYWGt/5ezd8kcpwPrm6zn9tNM/KtozbpfU6k=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
diff --git a/tests/tools/tools.go b/tests/tools/tools.go
new file mode 100644
index 0000000..05dd78c
--- /dev/null
+++ b/tests/tools/tools.go
@@ -0,0 +1,12 @@
+//go:build tools
+// +build tools
+
+package tools
+
+// Importing the packages here will allow to vendor those via
+// `go mod vendor`.
+
+import (
+ _ "github.com/cpuguy83/go-md2man"
+ _ "github.com/vbatts/git-validation"
+)