]> arthur.barton.de Git - bup.git/blob - t/test-meta.sh
Restore any metadata during "bup restore"; add "bup meta --edit".
[bup.git] / t / test-meta.sh
1 #!/usr/bin/env bash
2 . wvtest.sh
3
4 TOP="$(pwd)"
5 export BUP_DIR="$TOP/buptest.tmp"
6
7 bup()
8 {
9     "$TOP/bup" "$@"
10 }
11
12 # Very simple metadata tests -- create a test tree then check that bup
13 # meta can reproduce the metadata correctly (according to bup xstat)
14 # via create, extract, start-extract, and finish-extract.  The current
15 # tests are crude, and this does not fully test devices, varying
16 # users/groups, acls, attrs, etc.
17
18 genstat()
19 {
20     (
21         export PATH="$TOP:$PATH" # pick up bup
22         # Skip atime (test elsewhere) to avoid the observer effect.
23         find . | sort | xargs bup xstat --exclude-fields ctime,atime,size
24     )
25 }
26
27 actually-root()
28 {
29     test "$(whoami)" == root -a -z "$FAKEROOTKEY"
30 }
31
32 force-delete()
33 {
34     if ! actually-root; then
35         rm -rf "$@"
36     else
37         # Go to greater lengths to deal with any test detritus.
38         for f in "$@"; do
39             test -e "$@" || continue
40             chattr -fR = "$@" || true
41             setfacl -Rb "$@"
42             rm -r "$@"
43         done
44     fi
45 }
46
47 compare-trees()
48 {
49     (
50         set -e
51         set -o pipefail
52         tmpfile="$(mktemp)"
53         trap "rm -rf ${tmpfile}" EXIT
54         rsync -ni -aHAX "$1" "$2" > "${tmpfile}"
55         if test $(wc -l < "${tmpfile}") != 0; then
56             echo "ERROR: detected differences between $1 and $2"
57             cat "${tmpfile}"
58             false
59         fi
60     )
61 }
62
63 test-src-create-extract()
64 {
65     # Test bup meta create/extract for ./src -> ./src-restore.
66     # Also writes to ./src-stat and ./src-restore-stat.
67     (
68         (cd src && WVPASS genstat) > src-stat
69         WVPASS bup meta --create --recurse --file src.meta src
70         # Test extract.
71         force-delete src-restore
72         mkdir src-restore
73         cd src-restore
74         WVPASS bup meta --extract --file ../src.meta
75         WVPASS test -d src
76         (cd src && genstat >../../src-restore-stat) || WVFAIL
77         WVPASS diff -U5 ../src-stat ../src-restore-stat
78         # Test start/finish extract.
79         force-delete src
80         WVPASS bup meta --start-extract --file ../src.meta
81         WVPASS test -d src
82         WVPASS bup meta --finish-extract --file ../src.meta
83         (cd src && genstat >../../src-restore-stat) || WVFAIL
84         WVPASS diff -U5 ../src-stat ../src-restore-stat
85     )
86 }
87
88 test-src-save-restore()
89 {
90     # Test bup save/restore metadata for ./src -> ./src-restore.  Also
91     # writes to ./src.bup.  Note that for now this just tests the
92     # restore below src/, in order to avoid having to worry about
93     # operations that require root (like chown /home).
94     (
95         set -x
96         rm -rf src.bup
97         mkdir src.bup
98         export BUP_DIR=$(pwd)/src.bup
99         WVPASS bup init
100         WVPASS bup index src
101         WVPASS bup save -t -n src src
102         # Test extract.
103         force-delete src-restore
104         mkdir src-restore
105         WVPASS bup restore -C src-restore "/src/latest$(pwd)/"
106         WVPASS test -d src-restore/src
107         WVPASS compare-trees src/ src-restore/src/
108         rm -rf src.bup
109         set +x
110     )
111 }
112
113 if actually-root; then
114     umount "$TOP/bupmeta.tmp/testfs" || true
115 fi
116
117 setup-test-tree()
118 (
119     set -e
120     force-delete "$BUP_DIR"
121     force-delete "$TOP/bupmeta.tmp"
122     mkdir -p "$TOP/bupmeta.tmp/src"
123     cp -pPR Documentation cmd lib t "$TOP/bupmeta.tmp"/src
124
125     # Regression test for metadata sort order.  Previously, these two
126     # entries would sort in the wrong order because the metadata
127     # entries were being sorted by mangled name, but the index isn't.
128     dd if=/dev/zero of="$TOP/bupmeta.tmp"/src/foo bs=1k count=33
129     touch -d 2011-11-11 "$TOP/bupmeta.tmp"/src/foo
130     touch -d 2011-12-12 "$TOP/bupmeta.tmp"/src/foo-bar
131
132     t/mksock "$TOP/bupmeta.tmp/src/test-socket" || true
133 ) || WVFAIL
134
135 # Use the test tree to check bup meta.
136 WVSTART 'meta --create/--extract'
137 (
138     setup-test-tree
139     cd "$TOP/bupmeta.tmp"
140     test-src-create-extract
141
142     # Test a top-level file (not dir).
143     touch src-file
144     WVPASS bup meta -cf src-file.meta src-file
145     mkdir dest
146     cd dest
147     WVPASS bup meta -xf ../src-file.meta
148 )
149
150 # Use the test tree to check bup save/restore metadata.
151 WVSTART 'metadata save/restore (general)'
152 (
153     setup-test-tree
154     cd "$TOP/bupmeta.tmp"
155     test-src-save-restore
156 )
157
158 WVSTART 'meta --edit'
159 (
160     force-delete "$TOP/bupmeta.tmp"
161     mkdir "$TOP/bupmeta.tmp"
162     cd "$TOP/bupmeta.tmp"
163     mkdir src
164     WVPASS bup meta -cf src.meta src
165
166     WVPASS bup meta --edit --set-uid 0 src.meta | WVPASS bup meta -tvvf - \
167         | WVPASS grep -qE '^uid: 0'
168     WVPASS bup meta --edit --set-uid 1000 src.meta | WVPASS bup meta -tvvf - \
169         | WVPASS grep -qE '^uid: 1000'
170
171     WVPASS bup meta --edit --set-gid 0 src.meta | WVPASS bup meta -tvvf - \
172         | WVPASS grep -qE '^gid: 0'
173     WVPASS bup meta --edit --set-gid 1000 src.meta | WVPASS bup meta -tvvf - \
174         | WVPASS grep -qE '^gid: 1000'
175
176     WVPASS bup meta --edit --set-user foo src.meta | WVPASS bup meta -tvvf - \
177         | WVPASS grep -qE '^user: foo'
178     WVPASS bup meta --edit --set-user bar src.meta | WVPASS bup meta -tvvf - \
179         | WVPASS grep -qE '^user: bar'
180     WVPASS bup meta --edit --unset-user src.meta | WVPASS bup meta -tvvf - \
181         | WVPASS grep -qE '^user:'
182     WVPASS bup meta --edit --set-user bar --unset-user src.meta \
183         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user:'
184     WVPASS bup meta --edit --unset-user --set-user bar src.meta \
185         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^user: bar'
186
187     WVPASS bup meta --edit --set-group foo src.meta | WVPASS bup meta -tvvf - \
188         | WVPASS grep -qE '^group: foo'
189     WVPASS bup meta --edit --set-group bar src.meta | WVPASS bup meta -tvvf - \
190         | WVPASS grep -qE '^group: bar'
191     WVPASS bup meta --edit --unset-group src.meta | WVPASS bup meta -tvvf - \
192         | WVPASS grep -qE '^group:'
193     WVPASS bup meta --edit --set-group bar --unset-group src.meta \
194         | WVPASS bup meta -tvvf - | WVPASS grep -qE '^group:'
195     WVPASS bup meta --edit --unset-group --set-group bar src.meta \
196         | WVPASS bup meta -tvvf - | grep -qE '^group: bar'
197 )
198
199 # Test ownership restoration (when not root or fakeroot).
200 (
201     if test "$(whoami)" == root; then
202         exit 0
203     fi
204
205     WVSTART 'metadata (restoration of ownership)'
206     force-delete "$TOP/bupmeta.tmp"
207     mkdir "$TOP/bupmeta.tmp"
208     cd "$TOP/bupmeta.tmp"
209     touch src
210     WVPASS bup meta -cf src.meta src
211
212     mkdir dest
213     cd dest
214     # Make sure we don't change (or try to change) the user when not root.
215     WVPASS bup meta --edit --set-user root ../src.meta | WVPASS bup meta -x
216     WVPASS bup xstat src | WVPASS grep -qvE '^user: root'
217     rm -rf src
218     WVPASS bup meta --edit --unset-user --set-uid 0 ../src.meta \
219         | WVPASS bup meta -x
220     WVPASS bup xstat src | grep -qvE '^user: root'
221
222     # Make sure we can restore one of the user's groups.
223     user_groups="$(groups)"
224     last_group="$(echo ${user_groups/* /})"
225     rm -rf src
226     WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
227         | WVPASS bup meta -x
228     WVPASS bup xstat src | WVPASS grep -qE "^group: $last_group"
229
230     # Make sure we can restore one of the user's gids.
231     user_gids="$(id -G)"
232     last_gid="$(echo ${user_gids/* /})"
233     rm -rf src
234     WVPASS bup meta --edit --unset-group --set-gid "$last_gid" ../src.meta \
235         | WVPASS bup meta -x
236     WVPASS bup xstat src | WVPASS grep -qE "^gid: $last_gid"
237
238     # Test --numeric-ids (gid).
239     rm -rf src
240     current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
241     WVPASS bup meta --edit --set-group "$last_group" ../src.meta \
242         | WVPASS bup meta -x --numeric-ids
243     new_gidx=$(bup xstat src | grep -e '^gid:')
244     WVPASSEQ "$current_gidx" "$new_gidx"
245
246     # Test that restoring an unknown user works.
247     unknown_user=$("$TOP"/t/unknown-owner --user)
248     rm -rf src
249     current_uidx=$(bup meta -tvvf ../src.meta | grep -e '^uid:')
250     WVPASS bup meta --edit --set-user "$unknown_user" ../src.meta \
251         | WVPASS bup meta -x
252     new_uidx=$(bup xstat src | grep -e '^uid:')
253     WVPASSEQ "$current_uidx" "$new_uidx"
254
255     # Test that restoring an unknown group works.
256     unknown_group=$("$TOP"/t/unknown-owner --group)
257     rm -rf src
258     current_gidx=$(bup meta -tvvf ../src.meta | grep -e '^gid:')
259     WVPASS bup meta --edit --set-group "$unknown_group" ../src.meta \
260         | WVPASS bup meta -x
261     new_gidx=$(bup xstat src | grep -e '^gid:')
262     WVPASSEQ "$current_gidx" "$new_gidx"
263 )
264
265 # Test ownership restoration (when root or fakeroot).
266 (
267     if test "$(whoami)" != root; then
268         exit 0
269     fi
270
271     WVSTART 'metadata (restoration of ownership as root)'
272     force-delete "$TOP/bupmeta.tmp"
273     mkdir "$TOP/bupmeta.tmp"
274     cd "$TOP/bupmeta.tmp"
275     touch src
276     WVPASS bup meta -cf src.meta src
277
278     mkdir dest
279     chmod 700 dest # so we can't accidentally do something insecure
280     cd dest
281
282     # Make sure we can restore a uid.
283     WVPASS bup meta --edit --unset-user --set-uid 42 ../src.meta \
284         | WVPASS bup meta -x
285     WVPASS bup xstat src | WVPASS grep -qE '^uid: 42'
286
287     # Make sure we can restore a gid.
288     WVPASS bup meta --edit --unset-group --set-gid 42 ../src.meta \
289         | WVPASS bup meta -x
290     WVPASS bup xstat src | WVPASS grep -qE '^gid: 42'
291
292     some_user=$("$TOP"/t/some-owner --user)
293     some_group=$("$TOP"/t/some-owner --group)
294
295     # Try to restore a user (and see that user trumps uid when uid is not 0).
296     WVPASS bup meta --edit --set-uid 42 --set-user "$some_user" ../src.meta \
297         | WVPASS bup meta -x
298     WVPASS bup xstat src | WVPASS grep -qE "^user: $some_user"
299
300     # Try to restore a group (and see that group trumps gid when gid is not 0).
301     WVPASS bup meta --edit --set-gid 42 --set-group "$some_group" ../src.meta \
302         | WVPASS bup meta -x
303     WVPASS bup xstat src | WVPASS grep -qE "^group: $some_user"
304
305     # Make sure a uid of 0 trumps a non-root user.
306     WVPASS bup meta --edit --set-user "$some_user" ../src.meta \
307         | WVPASS bup meta -x
308     WVPASS bup xstat src | WVPASS grep -qvE "^user: $some_user"
309     WVPASS bup xstat src | WVPASS grep -qE "^uid: 0"
310
311     # Make sure a gid of 0 trumps a non-root group.
312     WVPASS bup meta --edit --set-group "$some_user" ../src.meta \
313         | WVPASS bup meta -x
314     WVPASS bup xstat src | WVPASS grep -qvE "^group: $some_group"
315     WVPASS bup xstat src | WVPASS grep -qE "^gid: 0"
316
317     # Test --numeric-ids (gid).  Note the name 'root' is not handled
318     # specially, so we use that here as the test group name.  We
319     # assume that the root group's gid is never 42.
320     rm -rf src
321     WVPASS bup meta --edit --set-group root --set-gid 42 ../src.meta \
322         | WVPASS bup meta -x --numeric-ids
323     new_gidx=$(bup xstat src | grep -e '^gid:')
324     WVPASSEQ "$new_gidx" 'gid: 42'
325
326     # Test --numeric-ids (uid).  Note the name 'root' is not handled
327     # specially, so we use that here as the test user name.  We assume
328     # that the root user's uid is never 42.
329     rm -rf src
330     WVPASS bup meta --edit --set-user root --set-uid 42 ../src.meta \
331         | WVPASS bup meta -x --numeric-ids
332     new_uidx=$(bup xstat src | grep -e '^uid:')
333     WVPASSEQ "$new_uidx" 'uid: 42'
334
335     # Test that restoring an unknown user works.
336     unknown_user=$("$TOP"/t/unknown-owners --user)
337     rm -rf src
338     WVPASS bup meta --edit --set-uid 42 --set-user "$unknown_user" ../src.meta \
339         | WVPASS bup meta -x
340     new_uidx=$(bup xstat src | grep -e '^uid:')
341     WVPASSEQ "$new_uidx" 'uid: 42'
342
343     # Test that restoring an unknown group works.
344     unknown_group=$("$TOP"/t/unknown-owners --group)
345     rm -rf src
346     WVPASS bup meta --edit \
347         --set-gid 42 --set-group "$unknown_group" ../src.meta \
348         | WVPASS bup meta -x
349     new_gidx=$(bup xstat src | grep -e '^gid:')
350     WVPASSEQ "$new_gidx" 'gid: 42'
351 )
352
353 # Root-only tests that require an FS with all the trimmings: ACLs,
354 # Linux attr, Linux xattr, etc.
355 if actually-root; then
356     (
357         # These tests are only likely to work under Linux for now
358         # (patches welcome).
359         [[ $(uname) =~ Linux ]] || exit 0
360
361         cleanup_at_exit()
362         {
363             cd "$TOP"
364             umount "$TOP/bupmeta.tmp/testfs" || true
365         }
366
367         trap cleanup_at_exit EXIT
368
369         WVSTART 'meta - general (as root)'
370         setup-test-tree
371         cd "$TOP/bupmeta.tmp"
372
373         umount testfs || true
374         dd if=/dev/zero of=testfs.img bs=1M count=32
375         mke2fs -F -j -m 0 testfs.img
376         mkdir testfs
377         mount -o loop,acl,user_xattr testfs.img testfs
378         # Hide, so that tests can't create risks.
379         chown root:root testfs
380         chmod 0700 testfs
381
382         #cp -a src testfs/src
383         cp -pPR src testfs/src
384         (cd testfs && test-src-create-extract)
385
386         WVSTART 'meta - atime (as root)'
387         force-delete testfs/src
388         mkdir testfs/src
389         (
390             mkdir testfs/src/foo
391             touch testfs/src/bar
392             PYTHONPATH="$TOP/lib" \
393                 python -c "from bup import xstat; \
394                 x = xstat.timespec_to_nsecs((42, 0));\
395                    xstat.utime('testfs/src/foo', (x, x));\
396                    xstat.utime('testfs/src/bar', (x, x));"
397             cd testfs
398             WVPASS bup meta -v --create --recurse --file src.meta src
399             bup meta -tvf src.meta
400             # Test extract.
401             force-delete src-restore
402             mkdir src-restore
403             cd src-restore
404             WVPASS bup meta --extract --file ../src.meta
405             WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
406             WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
407             # Test start/finish extract.
408             force-delete src
409             WVPASS bup meta --start-extract --file ../src.meta
410             WVPASS test -d src
411             WVPASS bup meta --finish-extract --file ../src.meta
412             WVPASSEQ "$(bup xstat --include-fields=atime src/foo)" "atime: 42"
413             WVPASSEQ "$(bup xstat --include-fields=atime src/bar)" "atime: 42"
414         )
415
416         WVSTART 'meta - Linux attr (as root)'
417         force-delete testfs/src
418         mkdir testfs/src
419         (
420             touch testfs/src/foo
421             mkdir testfs/src/bar
422             chattr +acdeijstuADST testfs/src/foo
423             chattr +acdeijstuADST testfs/src/bar
424             (cd testfs && test-src-create-extract)
425         )
426
427         WVSTART 'meta - Linux xattr (as root)'
428         force-delete testfs/src
429         mkdir testfs/src
430         (
431             touch testfs/src/foo
432             mkdir testfs/src/bar
433             attr -s foo -V bar testfs/src/foo
434             attr -s foo -V bar testfs/src/bar
435             (cd testfs && test-src-create-extract)
436         )
437
438         WVSTART 'meta - POSIX.1e ACLs (as root)'
439         force-delete testfs/src
440         mkdir testfs/src
441         (
442             touch testfs/src/foo
443             mkdir testfs/src/bar
444             setfacl -m u:root:r testfs/src/foo
445             setfacl -m u:root:r testfs/src/bar
446             (cd testfs && test-src-create-extract)
447         )
448     )
449 fi
450
451 exit 0