tests: avoid rare fp failure in du/move-dir-while-traversing
[coreutils.git] / tests / du / move-dir-while-traversing
blobd0969fecc4e5fb2a740a5ec10d7e6c20adef6f56
1 #!/bin/sh
2 # Trigger a failed assertion in coreutils-8.9 and earlier.
4 # Copyright (C) 2011 Free Software Foundation, Inc.
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 . "${srcdir=.}/init.sh"; path_prepend_ ../src
20 print_ver_ du
22 # We use a python-inotify script, so...
23 python -m pyinotify -h > /dev/null \
24 || skip_ 'python inotify package not installed'
26 # Move a directory "up" while du is processing its sub-directories.
27 # While du is processing a hierarchy .../B/C/D/... this script
28 # detects when du opens D/, and then moves C/ "up" one level
29 # so that it is a sibling of B/.
30 # Given the inherent race condition, we have to add enough "weight"
31 # under D/ so that in most cases, the monitor performs the single
32 # rename syscall before du finishes processing the subtree under D/.
34 cat <<'EOF' > inotify-watch-for-dir-access.py
35 #!/usr/bin/env python
36 import pyinotify as pn
37 import os,sys
39 dir = sys.argv[1]
40 dest_parent = os.path.dirname(os.path.dirname(dir))
41 dest = os.path.join(dest_parent, os.path.basename(dir))
43 class ProcessDir(pn.ProcessEvent):
45 def process_IN_OPEN(self, event):
46 os.rename(dir, dest)
47 sys.exit(0)
49 def process_default(self, event):
50 pass
52 wm = pn.WatchManager()
53 notifier = pn.Notifier(wm)
54 wm.watch_transient_file(dir, pn.IN_OPEN, ProcessDir)
55 sys.stdout.write('started\n')
56 sys.stdout.flush()
57 notifier.loop()
58 EOF
59 chmod a+x inotify-watch-for-dir-access.py
61 t=T/U
62 mkdir d2 || framework_failure_
63 long=d/e/f/g/h/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z
64 # One iteration of this loop creates a tree with which
65 # du sometimes completes its traversal before the above rename.
66 # Five iterations was not enough in 2 of 7 "make -j20 check" runs on a
67 # 6/12-core system. However, using "10", I saw no failure in 20 trials.
68 # Using 10 iterations was not enough, either.
69 # Using 50, I saw no failure in 200 trials.
70 for i in $(seq 50); do
71 mkdir -p $t/3/a/b/c/$i/$long || framework_failure_
72 done
74 # Prohibit suspension, which could otherwise cause a timeout-induced FP failure.
75 trap '' TSTP
77 timeout 6 ./inotify-watch-for-dir-access.py $t/3/a/b > start-msg &
79 # Wait for the watcher to start...
80 nonempty() { test -s start-msg || { sleep $1; return 1; }; }
81 retry_delay_ nonempty .1 5
83 # The above watches for an IN_OPEN event on $t/3/a/b,
84 # and when it triggers, moves the parent, $t/3/a, up one level
85 # so it's directly under $t.
87 du -a $t d2 2> err
88 # Before coreutils-8.10, du would abort.
89 test $? = 1 || fail=1
91 # check for the new diagnostic
92 printf "du: fts_read failed: $t/3/a/b: No such file or directory\n" > exp \
93 || fail=1
94 compare err exp || fail=1
96 Exit $fail