vfs_shadow_copy2: add a blackbox test suite
authorUri Simchoni <uri@samba.org>
Thu, 29 Oct 2015 20:24:30 +0000 (22:24 +0200)
committerMichael Adam <obnox@samba.org>
Wed, 13 Jan 2016 16:11:38 +0000 (17:11 +0100)
Add a blackbox test suite for vfs_shadow_copy2, testing
parameters mountpoint, basedir, snapdir, snapdirseverywhere,
and testing correct wide-link processing.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=11580

Signed-off-by: Uri Simchoni <uri@samba.org>
Reviewed-by: Michael Adam <obnox@samba.org>
Autobuild-User(master): Michael Adam <obnox@samba.org>
Autobuild-Date(master): Wed Jan 13 17:11:38 CET 2016 on sn-devel-144

selftest/target/Samba3.pm
source3/script/tests/test_shadow_copy.sh [new file with mode: 0755]
source3/selftest/tests.py

index 09066203e8621b4ab912b4dfba21fb5e44b08897..cd293a6c9bc018b31a56ace2df591cbfe9776db4 100755 (executable)
@@ -1126,6 +1126,15 @@ sub provision($$$$$$$$)
        my $widelinks_linkdir="$shrdir/widelinks_foo";
        push(@dirs,$widelinks_linkdir);
 
+       my $shadow_tstdir="$shrdir/shadow";
+       push(@dirs,$shadow_tstdir);
+       my $shadow_mntdir="$shadow_tstdir/mount";
+       push(@dirs,$shadow_mntdir);
+       my $shadow_basedir="$shadow_mntdir/base";
+       push(@dirs,$shadow_basedir);
+       my $shadow_shrdir="$shadow_basedir/share";
+       push(@dirs,$shadow_shrdir);
+
        # this gets autocreated by winbindd
        my $wbsockdir="$prefix_abs/winbindd";
        my $wbsockprivdir="$lockdir/winbindd_privileged";
@@ -1392,6 +1401,10 @@ sub provision($$$$$$$$)
        # fruit:copyfile is a global option
        fruit:copyfile = yes
 
+       #this does not mean that we use non-secure test env,
+       #it just means we ALLOW one to be configured.
+       allow insecure wide links = yes
+
        # Begin extra options
        $extra_options
        # End extra options
@@ -1553,6 +1566,62 @@ sub provision($$$$$$$$)
        shell_snap:delete command = $fake_snap_pl --delete
        # a relative path here fails, the snapshot dir is no longer found
        shadow:snapdir = $shrdir/.snapshots
+
+[shadow1]
+       path = $shadow_shrdir
+       comment = previous versions snapshots under mount point
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_mntdir
+
+[shadow2]
+       path = $shadow_shrdir
+       comment = previous versions snapshots outside mount point
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_mntdir
+       shadow:snapdir = $shadow_tstdir/.snapshots
+
+[shadow3]
+       path = $shadow_shrdir
+       comment = previous versions with subvolume snapshots, snapshots under base dir
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_mntdir
+       shadow:basedir = $shadow_basedir
+       shadow:snapdir = $shadow_basedir/.snapshots
+
+[shadow4]
+       path = $shadow_shrdir
+       comment = previous versions with subvolume snapshots, snapshots outside mount point
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_mntdir
+       shadow:basedir = $shadow_basedir
+       shadow:snapdir = $shadow_tstdir/.snapshots
+
+[shadow5]
+       path = $shadow_shrdir
+       comment = previous versions at volume root snapshots under mount point
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_shrdir
+
+[shadow6]
+       path = $shadow_shrdir
+       comment = previous versions at volume root snapshots outside mount point
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_shrdir
+       shadow:snapdir = $shadow_tstdir/.snapshots
+
+[shadow7]
+       path = $shadow_shrdir
+       comment = previous versions snapshots everywhere
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_mntdir
+       shadow:snapdirseverywhere = yes
+
+[shadow_wl]
+       path = $shadow_shrdir
+       comment = previous versions with wide links allowed
+       vfs objects = shadow_copy2
+       shadow:mountpoint = $shadow_mntdir
+       wide links = yes
        ";
        close(CONF);
 
diff --git a/source3/script/tests/test_shadow_copy.sh b/source3/script/tests/test_shadow_copy.sh
new file mode 100755 (executable)
index 0000000..eecd5b8
--- /dev/null
@@ -0,0 +1,290 @@
+#!/bin/bash
+#
+# Blackbox test for shadow_copy2 VFS.
+#
+
+if [ $# -lt 7 ]; then
+cat <<EOF
+Usage: test_shadow_copy SERVER SERVER_IP DOMAIN USERNAME PASSWORD WORKDIR SMBCLIENT
+EOF
+exit 1;
+fi
+
+SERVER=${1}
+SERVER_IP=${2}
+DOMAIN=${3}
+USERNAME=${4}
+PASSWORD=${5}
+WORKDIR=${6}
+SMBCLIENT=${7}
+shift 7
+SMBCLIENT="$VALGRIND ${SMBCLIENT}"
+ADDARGS="$*"
+
+incdir=`dirname $0`/../../../testprogs/blackbox
+. $incdir/subunit.sh
+
+SNAPSHOTS[0]='@GMT-2015.10.31-19.40.30'
+SNAPSHOTS[1]='@GMT-2016.10.31-19.40.30'
+SNAPSHOTS[2]='@GMT-2017.10.31-19.40.30'
+SNAPSHOTS[3]='@GMT-2018.10.31-19.40.30'
+SNAPSHOTS[4]='@GMT-2019.10.31-19.40.30'
+SNAPSHOTS[5]='@GMT-2020.10.31-19.40.30'
+SNAPSHOTS[6]='@GMT-2021.10.31-19.40.30'
+SNAPSHOTS[7]='@GMT-2022.10.31-19.40.30'
+SNAPSHOTS[8]='@GMT-2023.10.31-19.40.30'
+SNAPSHOTS[9]='@GMT-2024.10.31-19.40.30'
+
+# build a hierarchy of files, symlinks, and directories
+build_files()
+{
+    local rootdir
+    local prefix
+    local version
+    local destdir
+    rootdir=$1
+    prefix=$2
+    version=$3
+    if [ -n "$prefix" ] ; then
+        destdir=$rootdir/$prefix
+    else
+        destdir=$rootdir
+    fi
+
+    mkdir -p $destdir
+    if [ "$version" = "latest" ] ; then
+        #non-snapshot files
+        # for non-snapshot version, create legit files
+        # so that wide-link checks focus on snapshot files
+        touch $destdir/foo
+        mkdir -p $destdir/bar
+        touch $destdir/bar/baz
+        touch $destdir/bar/lfoo
+        touch $destdir/bar/letcpasswd
+        touch $destdir/bar/loutside
+    elif [ "$version" = "fullsnap" ] ; then
+        #snapshot files
+        touch $destdir/foo
+        mkdir -p $destdir/bar
+        touch $destdir/bar/baz
+        ln -fs ../foo $destdir/bar/lfoo
+        ln -fs /etc/passwd $destdir/bar/letcpasswd
+        ln -fs ../../outside $destdir/bar/loutside
+        touch `dirname $destdir`/outside
+    else #subshare snapshot - at bar
+        touch $destdir/baz
+        ln -fs ../foo $destdir/lfoo
+        ln -fs /etc/passwd $destdir/letcpasswd
+        ln -fs ../../outside $destdir/loutside
+        touch `dirname $destdir`/../outside
+    fi
+
+}
+
+# build a snapshots directory
+build_snapshots()
+{
+    local where     #where to build snapshots
+    local prefix    #prefix from snapshot dir to share root
+    local start     #timestamp index of first snapshot
+    local end       #timestamp index of last snapshot
+    local sub       #creat a snapshot of subtree of share
+    local snapdir
+    local snapname
+    local i
+    local version
+
+    where=$1
+    prefix=$2
+    start=$3
+    end=$4
+    sub=$5
+
+    snapdir=$where/.snapshots
+    mkdir -p $snapdir
+
+    version="fullsnap"
+    if [ "$sub" = "1" ] ; then
+        version="subsnap"
+        prefix=""
+
+        # a valid link target for an inner symlink -
+        # the link is not broken yet should be blocked
+        # by wide link checks
+        touch $snapdir/foo
+    fi
+
+    for i in `seq $start $end` ; do
+        snapname=${SNAPSHOTS[$i]}
+        mkdir $snapdir/$snapname
+        build_files $snapdir/$snapname "$prefix" $version
+    done
+}
+
+# Test listing previous versions of a file
+test_count_versions()
+{
+    local share
+    local path
+    local expected_count
+    local versions
+
+    share=$1
+    path=$2
+    expected_count=$3
+    versions=`$SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP -c "allinfo $path" | grep "^create_time:" | wc -l`
+    if [ "$versions" = "$expected_count" ] ; then
+        true
+    else
+        echo "expected $expected_count versions of $path, got $versions"
+        false
+    fi
+}
+
+# Test fetching a previous version of a file
+test_fetch_snap_file()
+{
+    local share
+    local path
+    local snapidx
+
+    share=$1
+    path=$2
+    snapidx=$3
+    $SMBCLIENT -U$USERNAME%$PASSWORD "//$SERVER/$share" -I $SERVER_IP \
+        -c "get ${SNAPSHOTS[$snapidx]}/$path $WORKDIR/foo"
+}
+
+test_shadow_copy_fixed()
+{
+    local share     #share to contact
+    local where     #where to place snapshots
+    local prefix    #prefix to files inside snapshot
+    local msg
+    local allow_wl
+    local ncopies_allowd
+    local ncopies_blocked
+
+    share=$1
+    where=$2
+    prefix=$3
+    msg=$4
+    allow_wl=$5
+
+    ncopies_allowed=4
+    ncopies_blocked=1
+    if [ -n "$allow_wl" ] ; then
+        ncopies_blocked=4
+    fi
+
+    #delete snapshots from previous tests
+    find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+    build_snapshots $WORKDIR/$where "$prefix" 0 2
+
+    testit "$msg - regular file" \
+        test_count_versions $share foo $ncopies_allowed || \
+        failed=`expr $failed + 1`
+
+    testit "$msg - regular file in subdir" \
+        test_count_versions $share bar/baz $ncopies_allowed || \
+        failed=`expr $failed + 1`
+
+    testit "$msg - local symlink" \
+        test_count_versions $share bar/lfoo $ncopies_allowed || \
+        failed=`expr $failed + 1`
+
+    testit "$msg - abs symlink outside" \
+        test_count_versions $share bar/letcpasswd $ncopies_blocked || \
+        failed=`expr $failed + 1`
+
+    testit "$msg - rel symlink outside" \
+        test_count_versions $share bar/loutside $ncopies_blocked || \
+        failed=`expr $failed + 1`
+}
+
+test_shadow_copy_everywhere()
+{
+    local share     #share to contact
+
+    share=$1
+
+    #delete snapshots from previous tests
+    find $WORKDIR -name ".snapshots" -exec rm -rf {} \; 1>/dev/null 2>&1
+    build_snapshots "$WORKDIR/mount" "base/share" 0 0
+    build_snapshots "$WORKDIR/mount/base" "share" 1 2
+    build_snapshots "$WORKDIR/mount/base/share" "" 3 5
+    build_snapshots "$WORKDIR/mount/base/share/bar" "" 6 9 1
+
+    testit "snapshots in each dir - regular file" \
+        test_count_versions $share foo 4 || \
+        failed=`expr $failed + 1`
+
+    testit "snapshots in each dir - regular file in subdir" \
+        test_count_versions $share bar/baz 5 || \
+        failed=`expr $failed + 1`
+
+    testit "snapshots in each dir - local symlink (but outside snapshot)" \
+        test_count_versions $share bar/lfoo 1 || \
+        failed=`expr $failed + 1`
+
+    testit "snapshots in each dir - abs symlink outside" \
+        test_count_versions $share bar/letcpasswd 1 || \
+        failed=`expr $failed + 1`
+
+    testit "snapshots in each dir - rel symlink outside" \
+        test_count_versions $share bar/loutside 1 || \
+        failed=`expr $failed + 1`
+
+    #the previous versions of the file bar/lfoo points to are outside its
+    #snapshot, and are not reachable. However, but previous versions
+    #taken at different, non-overlapping times higher up the
+    #hierarchy are still reachable.
+    testit "fetch a previous version of a regular file" \
+        test_fetch_snap_file $share "bar/baz" 6 || \
+        failed=`expr $failed + 1`
+
+    testit_expect_failure "fetch a (non-existent) previous version of a symlink" \
+        test_fetch_snap_file $share "bar/lfoo" 6 || \
+        failed=`expr $failed + 1`
+
+    testit "fetch a previous version of a symlink via browsing (1)" \
+        test_fetch_snap_file $share "bar/lfoo" 0 || \
+        failed=`expr $failed + 1`
+
+    testit "fetch a previous version of a symlink via browsing (2)" \
+        test_fetch_snap_file $share "bar/lfoo" 1 || \
+        failed=`expr $failed + 1`
+
+    testit "fetch a previous version of a symlink via browsing (3)" \
+        test_fetch_snap_file $share "bar/lfoo" 3 || \
+        failed=`expr $failed + 1`
+
+}
+
+#build "latest" files
+build_files $WORKDIR/mount base/share "latest"
+
+failed=0
+
+# a test with wide links allowed - also to verify that what's later
+# being blocked is a result of server security measures and not
+# a testing artifact.
+test_shadow_copy_fixed shadow_wl mount base/share "shadow copies with wide links allowed" 1
+
+# tests for a fixed snapshot location
+test_shadow_copy_fixed shadow1 mount base/share "full volume snapshots mounted under volume"
+test_shadow_copy_fixed shadow2 . base/share "full volume snapshots mounted outside volume"
+test_shadow_copy_fixed shadow3 mount/base share "sub volume snapshots mounted under snapshot point"
+test_shadow_copy_fixed shadow4 . share "sub volume snapshots mounted outside"
+test_shadow_copy_fixed shadow5 mount/base/share "" "full volume snapshots and share mounted under volume"
+test_shadow_copy_fixed shadow6 . "" "full volume snapshots and share mounted outside"
+
+# tests for snapshot everywhere - one snapshot location
+test_shadow_copy_fixed shadow7 mount base/share "'everywhere' full volume snapshots"
+test_shadow_copy_fixed shadow7 mount/base share "'everywhere' sub volume snapshots"
+test_shadow_copy_fixed shadow7 mount/base/share "" "'everywhere' share snapshots"
+
+# a test for snapshots everywhere - multiple snapshot locations
+test_shadow_copy_everywhere shadow7
+
+exit $failed
index 655c593b80e88fb292384d11072762e7ba922f95..25d20fe0f9d0a70260271572b2b8f2d135fea833 100755 (executable)
@@ -179,6 +179,7 @@ for env in ["fileserver"]:
     plantestsuite("samba3.blackbox.dfree_command (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_dfree_command.sh"), '$SERVER', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
     plantestsuite("samba3.blackbox.valid_users (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_valid_users.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$PREFIX', smbclient3])
     plantestsuite("samba3.blackbox.offline (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_offline.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/offline', smbclient3])
+    plantestsuite("samba3.blackbox.shadow_copy2 (%s)" % env, env, [os.path.join(samba3srcdir, "script/tests/test_shadow_copy.sh"), '$SERVER', '$SERVER_IP', '$DOMAIN', '$USERNAME', '$PASSWORD', '$LOCAL_PATH/shadow', smbclient3])
 
     #
     # tar command tests