6 export BUP_DIR="$TOP/buptest.tmp"
15 "$TOP/t/hardlink-sets" "$@"
18 # Very simple metadata tests -- create a test tree then check that bup
19 # meta can reproduce the metadata correctly (according to bup xstat)
20 # via create, extract, start-extract, and finish-extract. The current
21 # tests are crude, and this does not fully test devices, varying
22 # users/groups, acls, attrs, etc.
27 export PATH="$TOP:$PATH" # pick up bup
28 # Skip atime (test elsewhere) to avoid the observer effect.
29 find . | sort | xargs bup xstat --exclude-fields ctime,atime,size
33 test-src-create-extract()
35 # Test bup meta create/extract for ./src -> ./src-restore.
36 # Also writes to ./src-stat and ./src-restore-stat.
38 (cd src && WVPASS genstat) > src-stat
39 WVPASS bup meta --create --recurse --file src.meta src
41 force-delete src-restore
44 WVPASS bup meta --extract --file ../src.meta
46 (cd src && genstat >../../src-restore-stat) || WVFAIL
47 WVPASS diff -U5 ../src-stat ../src-restore-stat
48 # Test start/finish extract.
50 WVPASS bup meta --start-extract --file ../src.meta
52 WVPASS bup meta --finish-extract --file ../src.meta
53 (cd src && genstat >../../src-restore-stat) || WVFAIL
54 WVPASS diff -U5 ../src-stat ../src-restore-stat
58 test-src-save-restore()
60 # Test bup save/restore metadata for ./src -> ./src-restore. Also
61 # writes to ./src.bup. Note that for now this just tests the
62 # restore below src/, in order to avoid having to worry about
63 # operations that require root (like chown /home).
68 export BUP_DIR=$(pwd)/src.bup
71 WVPASS bup save -t -n src src
73 force-delete src-restore
75 WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
76 WVPASS test -d src-restore/src
77 WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
85 if [ $(t/root-status) != root ]; then return 0; fi
87 umount "$TOP/bupmeta.tmp/testfs" || true
88 umount "$TOP/bupmeta.tmp/testfs-limited" || true
92 trap universal-cleanup EXIT
97 force-delete "$BUP_DIR"
98 force-delete "$TOP/bupmeta.tmp"
99 mkdir -p "$TOP/bupmeta.tmp/src"
100 cp -pPR Documentation cmd lib t "$TOP/bupmeta.tmp"/src
102 # Add some hard links for the general tests.
104 cd "$TOP/bupmeta.tmp"/src
105 touch hardlink-target
106 ln hardlink-target hardlink-1
107 ln hardlink-target hardlink-2
108 ln hardlink-target hardlink-3
111 # Add some trivial files for the index, modify, save tests.
113 cd "$TOP/bupmeta.tmp"/src
115 touch volatile/{1,2,3}
118 # Regression test for metadata sort order. Previously, these two
119 # entries would sort in the wrong order because the metadata
120 # entries were being sorted by mangled name, but the index isn't.
121 dd if=/dev/zero of="$TOP/bupmeta.tmp"/src/foo bs=1k count=33
122 touch -t 201111111111 "$TOP/bupmeta.tmp"/src/foo
123 touch -t 201112121111 "$TOP/bupmeta.tmp"/src/foo-bar
125 t/mksock "$TOP/bupmeta.tmp/src/test-socket" || true
128 # Use the test tree to check bup meta.
129 WVSTART 'meta --create/--extract'
132 cd "$TOP/bupmeta.tmp"
133 test-src-create-extract
135 # Test a top-level file (not dir).
137 WVPASS bup meta -cf src-file.meta src-file
140 WVPASS bup meta -xf ../src-file.meta
143 # Use the test tree to check bup save/restore metadata.
144 WVSTART 'metadata save/restore (general)'
147 cd "$TOP/bupmeta.tmp"
148 test-src-save-restore
151 # Test that we pull the index (not filesystem) metadata for any
152 # unchanged files whenever we're saving other files in a given
154 WVSTART 'metadata save/restore (using index metadata)'
157 cd "$TOP/bupmeta.tmp"
159 # ...for now -- might be a problem with hardlink restores that was
160 # causing noise wrt this test.
163 # Pause here to keep the filesystem changes far enough away from
164 # the first index run that bup won't cap their index timestamps
165 # (see "bup help index" for more information). Without this
166 # sleep, the compare-trees test below "Bup should *not* pick up
167 # these metadata..." may fail.
173 export BUP_DIR=$(pwd)/src.bup
176 WVPASS bup save -t -n src src
178 force-delete src-restore-1
180 WVPASS bup restore -C src-restore-1 "/src/latest$(pwd)/"
181 WVPASS test -d src-restore-1/src
182 WVPASS "$TOP/t/compare-trees" -c src/ src-restore-1/src/
184 echo "blarg" > src/volatile/1
185 cp -a src/volatile/1 src-restore-1/src/volatile/
188 # Bup should *not* pick up these metadata changes.
191 WVPASS bup save -t -n src src
193 force-delete src-restore-2
195 WVPASS bup restore -C src-restore-2 "/src/latest$(pwd)/"
196 WVPASS test -d src-restore-2/src
197 WVPASS "$TOP/t/compare-trees" -c src-restore-1/src/ src-restore-2/src/
203 setup-hardlink-test()
206 cd "$TOP/bupmeta.tmp"
213 hardlink-test-run-restore()
215 force-delete src-restore
217 WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
218 WVPASS test -d src-restore/src
221 # Test hardlinks more carefully.
222 WVSTART 'metadata save/restore (hardlinks)'
226 export BUP_DIR="$TOP/bupmeta.tmp/src.bup"
227 force-delete "$TOP/bupmeta.tmp"
228 mkdir -p "$TOP/bupmeta.tmp"
230 cd "$TOP/bupmeta.tmp"
232 # Test trivial case - single hardlink.
235 cd "$TOP/bupmeta.tmp"/src
236 touch hardlink-target
237 ln hardlink-target hardlink-1
240 WVPASS bup save -t -n src src
241 hardlink-test-run-restore
242 WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
244 # Test the case where the hardlink hasn't changed, but the tree
245 # needs to be saved again. i.e. the save-cmd.py "if hashvalid:"
248 cd "$TOP/bupmeta.tmp"/src
249 echo whatever > something-new
252 WVPASS bup save -t -n src src
253 hardlink-test-run-restore
254 WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
256 # Test hardlink changes between index runs.
259 cd "$TOP/bupmeta.tmp"/src
260 touch hardlink-target-a
261 touch hardlink-target-b
262 ln hardlink-target-a hardlink-b-1
263 ln hardlink-target-a hardlink-a-1
265 WVPASS bup index -vv src
267 ln src/hardlink-target-b src/hardlink-b-1
268 WVPASS bup index -vv src
269 WVPASS bup save -t -n src src
270 hardlink-test-run-restore
271 echo ./src/hardlink-a-1 > hardlink-sets.expected
272 echo ./src/hardlink-target-a >> hardlink-sets.expected
273 echo >> hardlink-sets.expected
274 echo ./src/hardlink-b-1 >> hardlink-sets.expected
275 echo ./src/hardlink-target-b >> hardlink-sets.expected
276 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
277 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
279 # Test hardlink changes between index and save -- hardlink set [a
280 # b c d] changes to [a b] [c d]. At least right now bup should
281 # notice and recreate the latter.
283 cd "$TOP/bupmeta.tmp"/src
289 WVPASS bup index -vv src
293 WVPASS bup save -t -n src src
294 hardlink-test-run-restore
295 echo ./src/a > hardlink-sets.expected
296 echo ./src/b >> hardlink-sets.expected
297 echo >> hardlink-sets.expected
298 echo ./src/c >> hardlink-sets.expected
299 echo ./src/d >> hardlink-sets.expected
300 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
301 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
303 # Test that we don't link outside restore tree.
305 cd "$TOP/bupmeta.tmp"
309 WVPASS bup index -vv src
310 WVPASS bup save -t -n src src
311 force-delete src-restore
313 WVPASS bup restore -C src-restore "/src/latest$(pwd)/src/a/"
314 WVPASS test -e src-restore/1
315 echo -n > hardlink-sets.expected
316 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
317 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
319 # Test that we do link within separate sub-trees.
321 cd "$TOP/bupmeta.tmp"
325 WVPASS bup index -vv src/a src/b
326 WVPASS bup save -t -n src src/a src/b
327 hardlink-test-run-restore
328 echo ./src/a/1 > hardlink-sets.expected
329 echo ./src/b/1 >> hardlink-sets.expected
330 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
331 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
334 WVSTART 'meta --edit'
336 force-delete "$TOP/bupmeta.tmp"
337 mkdir "$TOP/bupmeta.tmp"
338 cd "$TOP/bupmeta.tmp"
340 WVPASS bup meta -cf src.meta src
342 WVPASS bup meta --edit --set-uid 0 src.meta | WVPASS bup meta -tvvf - \
343 | WVPASS grep -qE '^uid: 0'
344 WVPASS bup meta --edit --set-uid 1000 src.meta | WVPASS bup meta -tvvf - \
345 | WVPASS grep -qE '^uid: 1000'
347 WVPASS bup meta --edit --set-gid 0 src.meta | WVPASS bup meta -tvvf - \
348 | WVPASS grep -qE '^gid: 0'
349 WVPASS bup meta --edit --set-gid 1000 src.meta | WVPASS bup meta -tvvf - \
350 | WVPASS grep -qE '^gid: 1000'
352 WVPASS bup meta --edit --set-user foo src.meta | WVPASS bup meta -tvvf - \
353 | WVPASS grep -qE '^user: foo'
354 WVPASS bup meta --edit --set-user bar src.meta | WVPASS bup meta -tvvf - \
355 | WVPASS grep -qE '^user: bar'
356 WVPASS bup meta --edit --unset-user src.meta | WVPASS bup meta -tvvf - \
357 | WVPASS grep -qE '^user:'
358 WVPASS bup meta --edit --set-user bar --unset-user src.meta \
359 | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user:'
360 WVPASS bup meta --edit --unset-user --set-user bar src.meta \
361 | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user: bar'
363 WVPASS bup meta --edit --set-group foo src.meta | WVPASS bup meta -tvvf - \
364 | WVPASS grep -qE '^group: foo'
365 WVPASS bup meta --edit --set-group bar src.meta | WVPASS bup meta -tvvf - \
366 | WVPASS grep -qE '^group: bar'
367 WVPASS bup meta --edit --unset-group src.meta | WVPASS bup meta -tvvf - \
368 | WVPASS grep -qE '^group:'
369 WVPASS bup meta --edit --set-group bar --unset-group src.meta \
370 | WVPASS bup meta -tvvf - | WVPASS grep -qE '^group:'
371 WVPASS bup meta --edit --unset-group --set-group bar src.meta \
372 | WVPASS bup meta -tvvf - | grep -qE '^group: bar'
375 # Test ownership restoration (when not root or fakeroot).
377 if [ $(t/root-status) != none ]; then
381 WVSTART 'metadata (restoration of ownership)'
382 force-delete "$TOP/bupmeta.tmp"
383 mkdir "$TOP/bupmeta.tmp"
384 cd "$TOP/bupmeta.tmp"
386 WVPASS bup meta -cf src.meta src
390 # Make sure we don't change (or try to change) the user when not root.
391 WVPASS bup meta --edit --set-user root ../src.meta | WVPASS bup meta -x
392 WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
394 WVPASS bup meta --edit --unset-user --set-uid 0 ../src.meta \
396 WVPASS bup xstat src | grep -qvE '^user: root'
398 # Make sure we can restore one of the user's groups.
399 last_group="$(python -c 'import os,grp; \
400 print grp.getgrgid(os.getgroups()[0])[0]')"
402 WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
404 WVPASS bup xstat src | WVPASS grep -qE "^group: $last_group"
406 # Make sure we can restore one of the user's gids.
408 last_gid="$(echo ${user_gids/* /})"
410 WVPASS bup meta --edit --unset-group --set-gid "$last_gid" ../src.meta \
412 WVPASS bup xstat src | WVPASS grep -qE "^gid: $last_gid"
414 # Test --numeric-ids (gid).
416 current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
417 WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
418 | WVPASS bup meta -x --numeric-ids
419 new_gidx=$(bup xstat src | grep -e '^gid:')
420 WVPASSEQ "$current_gidx" "$new_gidx"
422 # Test that restoring an unknown user works.
423 unknown_user=$("$TOP"/t/unknown-owner --user)
425 current_uidx=$(bup meta -tvvf ../src.meta | grep -e '^uid:')
426 WVPASS bup meta --edit --set-user "$unknown_user" ../src.meta \
428 new_uidx=$(bup xstat src | grep -e '^uid:')
429 WVPASSEQ "$current_uidx" "$new_uidx"
431 # Test that restoring an unknown group works.
432 unknown_group=$("$TOP"/t/unknown-owner --group)
434 current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
435 WVPASS bup meta --edit --set-group "$unknown_group" ../src.meta \
437 new_gidx=$(bup xstat src | grep -e '^gid:')
438 WVPASSEQ "$current_gidx" "$new_gidx"
441 # Test ownership restoration (when root or fakeroot).
443 if [ $(t/root-status) == none ]; then
447 WVSTART 'metadata (restoration of ownership as root)'
448 force-delete "$TOP/bupmeta.tmp"
449 mkdir "$TOP/bupmeta.tmp"
450 cd "$TOP/bupmeta.tmp"
452 chown 0:0 src # In case the parent dir is sgid, etc.
453 WVPASS bup meta -cf src.meta src
456 chmod 700 dest # so we can't accidentally do something insecure
459 # Make sure we can restore a uid.
460 WVPASS bup meta --edit --unset-user --set-uid 42 ../src.meta \
462 WVPASS bup xstat src | WVPASS grep -qE '^uid: 42'
464 # Make sure we can restore a gid.
465 WVPASS bup meta --edit --unset-group --set-gid 42 ../src.meta \
467 WVPASS bup xstat src | WVPASS grep -qE '^gid: 42'
469 some_user=$("$TOP"/t/some-owner --user)
470 some_group=$("$TOP"/t/some-owner --group)
472 # Try to restore a user (and see that user trumps uid when uid is not 0).
473 WVPASS bup meta --edit --set-uid 42 --set-user "$some_user" ../src.meta \
475 WVPASS bup xstat src | WVPASS grep -qE "^user: $some_user"
477 # Try to restore a group (and see that group trumps gid when gid is not 0).
478 WVPASS bup meta --edit --set-gid 42 --set-group "$some_group" ../src.meta \
480 WVPASS bup xstat src | WVPASS grep -qE "^group: $some_user"
482 # Make sure a uid of 0 trumps a non-root user.
483 WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
485 WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
486 WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
488 # Make sure a gid of 0 trumps a non-root group.
489 WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
491 WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
492 WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
494 # Test --numeric-ids (gid). Note the name 'root' is not handled
495 # specially, so we use that here as the test group name. We
496 # assume that the root group's gid is never 42.
498 WVPASS bup meta --edit --set-group root --set-gid 42 ../src.meta \
499 | WVPASS bup meta -x --numeric-ids
500 new_gidx=$(bup xstat src | grep -e '^gid:')
501 WVPASSEQ "$new_gidx" 'gid: 42'
503 # Test --numeric-ids (uid). Note the name 'root' is not handled
504 # specially, so we use that here as the test user name. We assume
505 # that the root user's uid is never 42.
507 WVPASS bup meta --edit --set-user root --set-uid 42 ../src.meta \
508 | WVPASS bup meta -x --numeric-ids
509 new_uidx=$(bup xstat src | grep -e '^uid:')
510 WVPASSEQ "$new_uidx" 'uid: 42'
512 # Test that restoring an unknown user works.
513 unknown_user=$("$TOP"/t/unknown-owners --user)
515 WVPASS bup meta --edit --set-uid 42 --set-user "$unknown_user" ../src.meta \
517 new_uidx=$(bup xstat src | grep -e '^uid:')
518 WVPASSEQ "$new_uidx" 'uid: 42'
520 # Test that restoring an unknown group works.
521 unknown_group=$("$TOP"/t/unknown-owners --group)
523 WVPASS bup meta --edit \
524 --set-gid 42 --set-group "$unknown_group" ../src.meta \
526 new_gidx=$(bup xstat src | grep -e '^gid:')
527 WVPASSEQ "$new_gidx" 'gid: 42'
530 # Root-only tests that require an FS with all the trimmings: ACLs,
531 # Linux attr, Linux xattr, etc.
532 if [ $(t/root-status) == root ]; then
535 # Some cleanup handled in universal-cleanup() above.
536 # These tests are only likely to work under Linux for now
538 [[ $(uname) =~ Linux ]] || exit 0
540 WVSTART 'meta - general (as root)'
542 cd "$TOP/bupmeta.tmp"
544 umount testfs || true
545 dd if=/dev/zero of=testfs.img bs=1M count=32
546 mke2fs -F -j -m 0 testfs.img
548 mount -o loop,acl,user_xattr testfs.img testfs
549 # Hide, so that tests can't create risks.
550 chown root:root testfs
553 umount testfs-limited || true
554 dd if=/dev/zero of=testfs-limited.img bs=1M count=32
555 mkfs -t vfat testfs-limited.img
557 mount -o loop,uid=root,gid=root,umask=0077 \
558 testfs-limited.img testfs-limited
560 #cp -a src testfs/src
561 cp -pPR src testfs/src
562 (cd testfs && test-src-create-extract)
564 WVSTART 'meta - atime (as root)'
565 force-delete testfs/src
570 PYTHONPATH="$TOP/lib" \
571 python -c "from bup import xstat; \
572 x = xstat.timespec_to_nsecs((42, 0));\
573 xstat.utime('testfs/src/foo', (x, x));\
574 xstat.utime('testfs/src/bar', (x, x));"
576 WVPASS bup meta -v --create --recurse --file src.meta src
577 bup meta -tvf src.meta
579 force-delete src-restore
582 WVPASS bup meta --extract --file ../src.meta
583 WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
584 WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
585 # Test start/finish extract.
587 WVPASS bup meta --start-extract --file ../src.meta
589 WVPASS bup meta --finish-extract --file ../src.meta
590 WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
591 WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
594 WVSTART 'meta - Linux attr (as root)'
595 force-delete testfs/src
600 chattr +acdeijstuADST testfs/src/foo
601 chattr +acdeijstuADST testfs/src/bar
602 (cd testfs && test-src-create-extract)
603 # Test restoration to a limited filesystem (vfat).
605 WVPASS bup meta --create --recurse --file testfs/src.meta \
607 force-delete testfs-limited/src-restore
608 mkdir testfs-limited/src-restore
609 cd testfs-limited/src-restore
610 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
611 | WVPASS grep -e '^Linux chattr:' \
613 'import sys; exit(not len(sys.stdin.readlines()) == 2)'
617 WVSTART 'meta - Linux xattr (as root)'
618 force-delete testfs/src
623 attr -s foo -V bar testfs/src/foo
624 attr -s foo -V bar testfs/src/bar
625 (cd testfs && test-src-create-extract)
627 # Test restoration to a limited filesystem (vfat).
629 WVPASS bup meta --create --recurse --file testfs/src.meta \
631 force-delete testfs-limited/src-restore
632 mkdir testfs-limited/src-restore
633 cd testfs-limited/src-restore
634 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
635 | WVPASS grep -e '^xattr\.set:' \
637 'import sys; exit(not len(sys.stdin.readlines()) == 2)'
641 WVSTART 'meta - POSIX.1e ACLs (as root)'
642 force-delete testfs/src
647 setfacl -m u:root:r testfs/src/foo
648 setfacl -m u:root:r testfs/src/bar
649 (cd testfs && test-src-create-extract)
651 # Test restoration to a limited filesystem (vfat).
653 WVPASS bup meta --create --recurse --file testfs/src.meta \
655 force-delete testfs-limited/src-restore
656 mkdir testfs-limited/src-restore
657 cd testfs-limited/src-restore
658 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
659 | WVPASS grep -e '^POSIX1e ACL applyto:' \
661 'import sys; exit(not len(sys.stdin.readlines()) == 2)'