1 # This gdb Python script runs notmuch new and simulates killing and
2 # restarting notmuch new after every Xapian commit. To simulate this
3 # more efficiently, this script runs notmuch new and, immediately
4 # after every Xapian commit, it *pauses* the running notmuch new,
5 # copies the entire database and maildir to a snapshot directory, and
6 # executes a full notmuch new on that snapshot, comparing the final
7 # results with the expected output. It can then resume the paused
8 # notmuch new, which is still running on the original maildir, and
17 gdb.execute('set args new')
19 # Make Xapian commit after every operation instead of batching
20 gdb.execute('set environment XAPIAN_FLUSH_THRESHOLD = 1')
22 maildir = os.environ['MAIL_DIR']
24 # Trap calls to rename, which happens just before Xapian commits
25 class RenameBreakpoint(gdb.Breakpoint):
26 def __init__(self, *args, **kwargs):
27 super(RenameBreakpoint, self).__init__(*args, **kwargs)
32 xapiandir = '%s/.notmuch/xapian' % maildir
33 if os.path.isfile('%s/iamchert' % xapiandir):
34 # As an optimization, only consider snapshots after a
35 # Xapian has really committed. The chert backend
36 # overwrites record.base? as the last step in the commit,
37 # so keep an eye on their inumbers.
39 for path in glob.glob('%s/record.base*' % xapiandir):
40 inodes[path] = os.stat(path).st_ino
41 if inodes == self.last_inodes:
44 self.last_inodes = inodes
46 # Save a backtrace in case the test does fail
47 backtrace = gdb.execute('backtrace', to_string=True)
48 open('backtrace.%d' % self.n, 'w').write(backtrace)
50 # Snapshot the database
51 shutil.rmtree('%s.snap/.notmuch' % maildir)
52 shutil.copytree('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)
53 # Restore the mtime of $MAIL_DIR.snap/
54 shutil.copystat('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)
56 # Run notmuch new to completion on the snapshot
57 env = os.environ.copy()
58 env.update(NOTMUCH_CONFIG=os.environ['NOTMUCH_CONFIG'] + '.snap',
59 XAPIAN_FLUSH_THRESHOLD='1000')
60 subprocess.check_call(
61 ['notmuch', 'new'], env=env, stdout=open('/dev/null', 'w'))
62 subprocess.check_call(
63 ['notmuch', 'search', '*'], env=env,
64 stdout=open('search.%d' % self.n, 'w'))
66 # Tell the shell how far we've gotten
67 open('outcount', 'w').write(str(self.n + 1))
72 RenameBreakpoint('rename')
78 raise SystemExit(traceback.format_exc())