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
35 test "$(whoami)" == root -a -z "$FAKEROOTKEY"
38 test-src-create-extract()
40 # Test bup meta create/extract for ./src -> ./src-restore.
41 # Also writes to ./src-stat and ./src-restore-stat.
43 (cd src && WVPASS genstat) > src-stat
44 WVPASS bup meta --create --recurse --file src.meta src
46 force-delete src-restore
49 WVPASS bup meta --extract --file ../src.meta
51 (cd src && genstat >../../src-restore-stat) || WVFAIL
52 WVPASS diff -U5 ../src-stat ../src-restore-stat
53 # Test start/finish extract.
55 WVPASS bup meta --start-extract --file ../src.meta
57 WVPASS bup meta --finish-extract --file ../src.meta
58 (cd src && genstat >../../src-restore-stat) || WVFAIL
59 WVPASS diff -U5 ../src-stat ../src-restore-stat
63 test-src-save-restore()
65 # Test bup save/restore metadata for ./src -> ./src-restore. Also
66 # writes to ./src.bup. Note that for now this just tests the
67 # restore below src/, in order to avoid having to worry about
68 # operations that require root (like chown /home).
73 export BUP_DIR=$(pwd)/src.bup
76 WVPASS bup save -t -n src src
78 force-delete src-restore
80 WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
81 WVPASS test -d src-restore/src
82 WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
90 if ! actually-root; then return 0; fi
92 umount "$TOP/bupmeta.tmp/testfs" || true
93 umount "$TOP/bupmeta.tmp/testfs-limited" || true
97 trap universal-cleanup EXIT
102 force-delete "$BUP_DIR"
103 force-delete "$TOP/bupmeta.tmp"
104 mkdir -p "$TOP/bupmeta.tmp/src"
105 cp -pPR Documentation cmd lib t "$TOP/bupmeta.tmp"/src
107 # Add some hard links for the general tests.
109 cd "$TOP/bupmeta.tmp"/src
110 touch hardlink-target
111 ln hardlink-target hardlink-1
112 ln hardlink-target hardlink-2
113 ln hardlink-target hardlink-3
116 # Add some trivial files for the index, modify, save tests.
118 cd "$TOP/bupmeta.tmp"/src
120 touch volatile/{1,2,3}
123 # Regression test for metadata sort order. Previously, these two
124 # entries would sort in the wrong order because the metadata
125 # entries were being sorted by mangled name, but the index isn't.
126 dd if=/dev/zero of="$TOP/bupmeta.tmp"/src/foo bs=1k count=33
127 touch -d 2011-11-11 "$TOP/bupmeta.tmp"/src/foo
128 touch -d 2011-12-12 "$TOP/bupmeta.tmp"/src/foo-bar
130 t/mksock "$TOP/bupmeta.tmp/src/test-socket" || true
133 # Use the test tree to check bup meta.
134 WVSTART 'meta --create/--extract'
137 cd "$TOP/bupmeta.tmp"
138 test-src-create-extract
140 # Test a top-level file (not dir).
142 WVPASS bup meta -cf src-file.meta src-file
145 WVPASS bup meta -xf ../src-file.meta
148 # Use the test tree to check bup save/restore metadata.
149 WVSTART 'metadata save/restore (general)'
152 cd "$TOP/bupmeta.tmp"
153 test-src-save-restore
156 # Test that we pull the index (not filesystem) metadata for any
157 # unchanged files whenever we're saving other files in a given
159 WVSTART 'metadata save/restore (using index metadata)'
162 cd "$TOP/bupmeta.tmp"
164 # ...for now -- might be a problem with hardlink restores that was
165 # causing noise wrt this test.
168 # Pause here to keep the filesystem changes far enough away from
169 # the first index run that bup won't cap their index timestamps
170 # (see "bup help index" for more information). Without this
171 # sleep, the compare-trees test below "Bup should *not* pick up
172 # these metadata..." may fail.
178 export BUP_DIR=$(pwd)/src.bup
181 WVPASS bup save -t -n src src
183 force-delete src-restore-1
185 WVPASS bup restore -C src-restore-1 "/src/latest$(pwd)/"
186 WVPASS test -d src-restore-1/src
187 WVPASS "$TOP/t/compare-trees" -c src/ src-restore-1/src/
189 echo "blarg" > src/volatile/1
190 cp -a src/volatile/1 src-restore-1/src/volatile/
193 # Bup should *not* pick up these metadata changes.
196 WVPASS bup save -t -n src src
198 force-delete src-restore-2
200 WVPASS bup restore -C src-restore-2 "/src/latest$(pwd)/"
201 WVPASS test -d src-restore-2/src
202 WVPASS "$TOP/t/compare-trees" -c src-restore-1/src/ src-restore-2/src/
208 setup-hardlink-test()
211 cd "$TOP/bupmeta.tmp"
218 hardlink-test-run-restore()
220 force-delete src-restore
222 WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
223 WVPASS test -d src-restore/src
226 # Test hardlinks more carefully.
227 WVSTART 'metadata save/restore (hardlinks)'
231 export BUP_DIR="$TOP/bupmeta.tmp/src.bup"
232 force-delete "$TOP/bupmeta.tmp"
233 mkdir -p "$TOP/bupmeta.tmp"
235 cd "$TOP/bupmeta.tmp"
237 # Test trivial case - single hardlink.
240 cd "$TOP/bupmeta.tmp"/src
241 touch hardlink-target
242 ln hardlink-target hardlink-1
245 WVPASS bup save -t -n src src
246 hardlink-test-run-restore
247 WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
249 # Test the case where the hardlink hasn't changed, but the tree
250 # needs to be saved again. i.e. the save-cmd.py "if hashvalid:"
253 cd "$TOP/bupmeta.tmp"/src
254 echo whatever > something-new
257 WVPASS bup save -t -n src src
258 hardlink-test-run-restore
259 WVPASS "$TOP/t/compare-trees" -c src/ src-restore/src/
261 # Test hardlink changes between index runs.
264 cd "$TOP/bupmeta.tmp"/src
265 touch hardlink-target-a
266 touch hardlink-target-b
267 ln hardlink-target-a hardlink-b-1
268 ln hardlink-target-a hardlink-a-1
270 WVPASS bup index -vv src
272 ln src/hardlink-target-b src/hardlink-b-1
273 WVPASS bup index -vv src
274 WVPASS bup save -t -n src src
275 hardlink-test-run-restore
276 echo ./src/hardlink-a-1 > hardlink-sets.expected
277 echo ./src/hardlink-target-a >> hardlink-sets.expected
278 echo >> hardlink-sets.expected
279 echo ./src/hardlink-b-1 >> hardlink-sets.expected
280 echo ./src/hardlink-target-b >> hardlink-sets.expected
281 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
282 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
284 # Test hardlink changes between index and save -- hardlink set [a
285 # b c d] changes to [a b] [c d]. At least right now bup should
286 # notice and recreate the latter.
288 cd "$TOP/bupmeta.tmp"/src
294 WVPASS bup index -vv src
298 WVPASS bup save -t -n src src
299 hardlink-test-run-restore
300 echo ./src/a > hardlink-sets.expected
301 echo ./src/b >> hardlink-sets.expected
302 echo >> hardlink-sets.expected
303 echo ./src/c >> hardlink-sets.expected
304 echo ./src/d >> hardlink-sets.expected
305 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
306 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
308 # Test that we don't link outside restore tree.
310 cd "$TOP/bupmeta.tmp"
314 WVPASS bup index -vv src
315 WVPASS bup save -t -n src src
316 force-delete src-restore
318 WVPASS bup restore -C src-restore "/src/latest$(pwd)/src/a/"
319 WVPASS test -e src-restore/1
320 echo -n > hardlink-sets.expected
321 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
322 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
324 # Test that we do link within separate sub-trees.
326 cd "$TOP/bupmeta.tmp"
330 WVPASS bup index -vv src/a src/b
331 WVPASS bup save -t -n src src/a src/b
332 hardlink-test-run-restore
333 echo ./src/a/1 > hardlink-sets.expected
334 echo ./src/b/1 >> hardlink-sets.expected
335 (cd src-restore && hardlink-sets .) > hardlink-sets.restored
336 WVPASS diff -u hardlink-sets.expected hardlink-sets.restored
339 WVSTART 'meta --edit'
341 force-delete "$TOP/bupmeta.tmp"
342 mkdir "$TOP/bupmeta.tmp"
343 cd "$TOP/bupmeta.tmp"
345 WVPASS bup meta -cf src.meta src
347 WVPASS bup meta --edit --set-uid 0 src.meta | WVPASS bup meta -tvvf - \
348 | WVPASS grep -qE '^uid: 0'
349 WVPASS bup meta --edit --set-uid 1000 src.meta | WVPASS bup meta -tvvf - \
350 | WVPASS grep -qE '^uid: 1000'
352 WVPASS bup meta --edit --set-gid 0 src.meta | WVPASS bup meta -tvvf - \
353 | WVPASS grep -qE '^gid: 0'
354 WVPASS bup meta --edit --set-gid 1000 src.meta | WVPASS bup meta -tvvf - \
355 | WVPASS grep -qE '^gid: 1000'
357 WVPASS bup meta --edit --set-user foo src.meta | WVPASS bup meta -tvvf - \
358 | WVPASS grep -qE '^user: foo'
359 WVPASS bup meta --edit --set-user bar src.meta | WVPASS bup meta -tvvf - \
360 | WVPASS grep -qE '^user: bar'
361 WVPASS bup meta --edit --unset-user src.meta | WVPASS bup meta -tvvf - \
362 | WVPASS grep -qE '^user:'
363 WVPASS bup meta --edit --set-user bar --unset-user src.meta \
364 | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user:'
365 WVPASS bup meta --edit --unset-user --set-user bar src.meta \
366 | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user: bar'
368 WVPASS bup meta --edit --set-group foo src.meta | WVPASS bup meta -tvvf - \
369 | WVPASS grep -qE '^group: foo'
370 WVPASS bup meta --edit --set-group bar src.meta | WVPASS bup meta -tvvf - \
371 | WVPASS grep -qE '^group: bar'
372 WVPASS bup meta --edit --unset-group src.meta | WVPASS bup meta -tvvf - \
373 | WVPASS grep -qE '^group:'
374 WVPASS bup meta --edit --set-group bar --unset-group src.meta \
375 | WVPASS bup meta -tvvf - | WVPASS grep -qE '^group:'
376 WVPASS bup meta --edit --unset-group --set-group bar src.meta \
377 | WVPASS bup meta -tvvf - | grep -qE '^group: bar'
380 # Test ownership restoration (when not root or fakeroot).
382 if test "$(whoami)" == root; then
386 WVSTART 'metadata (restoration of ownership)'
387 force-delete "$TOP/bupmeta.tmp"
388 mkdir "$TOP/bupmeta.tmp"
389 cd "$TOP/bupmeta.tmp"
391 WVPASS bup meta -cf src.meta src
395 # Make sure we don't change (or try to change) the user when not root.
396 WVPASS bup meta --edit --set-user root ../src.meta | WVPASS bup meta -x
397 WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
399 WVPASS bup meta --edit --unset-user --set-uid 0 ../src.meta \
401 WVPASS bup xstat src | grep -qvE '^user: root'
403 # Make sure we can restore one of the user's groups.
404 last_group="$(python -c 'import os,grp; \
405 print grp.getgrgid(os.getgroups()[0])[0]')"
407 WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
409 WVPASS bup xstat src | WVPASS grep -qE "^group: $last_group"
411 # Make sure we can restore one of the user's gids.
413 last_gid="$(echo ${user_gids/* /})"
415 WVPASS bup meta --edit --unset-group --set-gid "$last_gid" ../src.meta \
417 WVPASS bup xstat src | WVPASS grep -qE "^gid: $last_gid"
419 # Test --numeric-ids (gid).
421 current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
422 WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
423 | WVPASS bup meta -x --numeric-ids
424 new_gidx=$(bup xstat src | grep -e '^gid:')
425 WVPASSEQ "$current_gidx" "$new_gidx"
427 # Test that restoring an unknown user works.
428 unknown_user=$("$TOP"/t/unknown-owner --user)
430 current_uidx=$(bup meta -tvvf ../src.meta | grep -e '^uid:')
431 WVPASS bup meta --edit --set-user "$unknown_user" ../src.meta \
433 new_uidx=$(bup xstat src | grep -e '^uid:')
434 WVPASSEQ "$current_uidx" "$new_uidx"
436 # Test that restoring an unknown group works.
437 unknown_group=$("$TOP"/t/unknown-owner --group)
439 current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
440 WVPASS bup meta --edit --set-group "$unknown_group" ../src.meta \
442 new_gidx=$(bup xstat src | grep -e '^gid:')
443 WVPASSEQ "$current_gidx" "$new_gidx"
446 # Test ownership restoration (when root or fakeroot).
448 if test "$(whoami)" != root; then
452 WVSTART 'metadata (restoration of ownership as root)'
453 force-delete "$TOP/bupmeta.tmp"
454 mkdir "$TOP/bupmeta.tmp"
455 cd "$TOP/bupmeta.tmp"
457 chown 0:0 src # In case the parent dir is sgid, etc.
458 WVPASS bup meta -cf src.meta src
461 chmod 700 dest # so we can't accidentally do something insecure
464 # Make sure we can restore a uid.
465 WVPASS bup meta --edit --unset-user --set-uid 42 ../src.meta \
467 WVPASS bup xstat src | WVPASS grep -qE '^uid: 42'
469 # Make sure we can restore a gid.
470 WVPASS bup meta --edit --unset-group --set-gid 42 ../src.meta \
472 WVPASS bup xstat src | WVPASS grep -qE '^gid: 42'
474 some_user=$("$TOP"/t/some-owner --user)
475 some_group=$("$TOP"/t/some-owner --group)
477 # Try to restore a user (and see that user trumps uid when uid is not 0).
478 WVPASS bup meta --edit --set-uid 42 --set-user "$some_user" ../src.meta \
480 WVPASS bup xstat src | WVPASS grep -qE "^user: $some_user"
482 # Try to restore a group (and see that group trumps gid when gid is not 0).
483 WVPASS bup meta --edit --set-gid 42 --set-group "$some_group" ../src.meta \
485 WVPASS bup xstat src | WVPASS grep -qE "^group: $some_user"
487 # Make sure a uid of 0 trumps a non-root user.
488 WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
490 WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
491 WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
493 # Make sure a gid of 0 trumps a non-root group.
494 WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
496 WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
497 WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
499 # Test --numeric-ids (gid). Note the name 'root' is not handled
500 # specially, so we use that here as the test group name. We
501 # assume that the root group's gid is never 42.
503 WVPASS bup meta --edit --set-group root --set-gid 42 ../src.meta \
504 | WVPASS bup meta -x --numeric-ids
505 new_gidx=$(bup xstat src | grep -e '^gid:')
506 WVPASSEQ "$new_gidx" 'gid: 42'
508 # Test --numeric-ids (uid). Note the name 'root' is not handled
509 # specially, so we use that here as the test user name. We assume
510 # that the root user's uid is never 42.
512 WVPASS bup meta --edit --set-user root --set-uid 42 ../src.meta \
513 | WVPASS bup meta -x --numeric-ids
514 new_uidx=$(bup xstat src | grep -e '^uid:')
515 WVPASSEQ "$new_uidx" 'uid: 42'
517 # Test that restoring an unknown user works.
518 unknown_user=$("$TOP"/t/unknown-owners --user)
520 WVPASS bup meta --edit --set-uid 42 --set-user "$unknown_user" ../src.meta \
522 new_uidx=$(bup xstat src | grep -e '^uid:')
523 WVPASSEQ "$new_uidx" 'uid: 42'
525 # Test that restoring an unknown group works.
526 unknown_group=$("$TOP"/t/unknown-owners --group)
528 WVPASS bup meta --edit \
529 --set-gid 42 --set-group "$unknown_group" ../src.meta \
531 new_gidx=$(bup xstat src | grep -e '^gid:')
532 WVPASSEQ "$new_gidx" 'gid: 42'
535 # Root-only tests that require an FS with all the trimmings: ACLs,
536 # Linux attr, Linux xattr, etc.
537 if actually-root; then
540 # Some cleanup handled in universal-cleanup() above.
541 # These tests are only likely to work under Linux for now
543 [[ $(uname) =~ Linux ]] || exit 0
545 WVSTART 'meta - general (as root)'
547 cd "$TOP/bupmeta.tmp"
549 umount testfs || true
550 dd if=/dev/zero of=testfs.img bs=1M count=32
551 mke2fs -F -j -m 0 testfs.img
553 mount -o loop,acl,user_xattr testfs.img testfs
554 # Hide, so that tests can't create risks.
555 chown root:root testfs
558 umount testfs-limited || true
559 dd if=/dev/zero of=testfs-limited.img bs=1M count=32
560 mkfs -t vfat testfs-limited.img
562 mount -o loop,uid=root,gid=root,umask=0077 \
563 testfs-limited.img testfs-limited
565 #cp -a src testfs/src
566 cp -pPR src testfs/src
567 (cd testfs && test-src-create-extract)
569 WVSTART 'meta - atime (as root)'
570 force-delete testfs/src
575 PYTHONPATH="$TOP/lib" \
576 python -c "from bup import xstat; \
577 x = xstat.timespec_to_nsecs((42, 0));\
578 xstat.utime('testfs/src/foo', (x, x));\
579 xstat.utime('testfs/src/bar', (x, x));"
581 WVPASS bup meta -v --create --recurse --file src.meta src
582 bup meta -tvf src.meta
584 force-delete src-restore
587 WVPASS bup meta --extract --file ../src.meta
588 WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
589 WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
590 # Test start/finish extract.
592 WVPASS bup meta --start-extract --file ../src.meta
594 WVPASS bup meta --finish-extract --file ../src.meta
595 WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
596 WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
599 WVSTART 'meta - Linux attr (as root)'
600 force-delete testfs/src
605 chattr +acdeijstuADST testfs/src/foo
606 chattr +acdeijstuADST testfs/src/bar
607 (cd testfs && test-src-create-extract)
608 # Test restoration to a limited filesystem (vfat).
610 WVPASS bup meta --create --recurse --file testfs/src.meta \
612 force-delete testfs-limited/src-restore
613 mkdir testfs-limited/src-restore
614 cd testfs-limited/src-restore
615 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
616 | WVPASS grep -e '^Linux chattr:' \
618 'import sys; exit(not len(sys.stdin.readlines()) == 2)'
622 WVSTART 'meta - Linux xattr (as root)'
623 force-delete testfs/src
628 attr -s foo -V bar testfs/src/foo
629 attr -s foo -V bar testfs/src/bar
630 (cd testfs && test-src-create-extract)
632 # Test restoration to a limited filesystem (vfat).
634 WVPASS bup meta --create --recurse --file testfs/src.meta \
636 force-delete testfs-limited/src-restore
637 mkdir testfs-limited/src-restore
638 cd testfs-limited/src-restore
639 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
640 | WVPASS grep -e '^xattr\.set:' \
642 'import sys; exit(not len(sys.stdin.readlines()) == 2)'
646 WVSTART 'meta - POSIX.1e ACLs (as root)'
647 force-delete testfs/src
652 setfacl -m u:root:r testfs/src/foo
653 setfacl -m u:root:r testfs/src/bar
654 (cd testfs && test-src-create-extract)
656 # Test restoration to a limited filesystem (vfat).
658 WVPASS bup meta --create --recurse --file testfs/src.meta \
660 force-delete testfs-limited/src-restore
661 mkdir testfs-limited/src-restore
662 cd testfs-limited/src-restore
663 WVFAIL bup meta --extract --file ../../testfs/src.meta 2>&1 \
664 | WVPASS grep -e '^POSIX1e ACL applyto:' \
666 'import sys; exit(not len(sys.stdin.readlines()) == 2)'