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 # As an optimization, only consider snapshots after a Xapian
33 # has really committed. Xapian overwrites record.base? as the
34 # last step in the commit, so keep an eye on their inumbers.
36 for path in glob.glob('%s/.notmuch/xapian/record.base*' % maildir):
37 inodes[path] = os.stat(path).st_ino
38 if inodes == self.last_inodes:
41 self.last_inodes = inodes
43 # Save a backtrace in case the test does fail
44 backtrace = gdb.execute('backtrace', to_string=True)
45 open('backtrace.%d' % self.n, 'w').write(backtrace)
47 # Snapshot the database
48 shutil.rmtree('%s.snap/.notmuch' % maildir)
49 shutil.copytree('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)
50 # Restore the mtime of $MAIL_DIR.snap/
51 shutil.copystat('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)
53 # Run notmuch new to completion on the snapshot
54 env = os.environ.copy()
55 env.update(NOTMUCH_CONFIG=os.environ['NOTMUCH_CONFIG'] + '.snap',
56 XAPIAN_FLUSH_THRESHOLD='1000')
57 subprocess.check_call(
58 ['notmuch', 'new'], env=env, stdout=open('/dev/null', 'w'))
59 subprocess.check_call(
60 ['notmuch', 'search', '*'], env=env,
61 stdout=open('search.%d' % self.n, 'w'))
63 # Tell the shell how far we've gotten
64 open('outcount', 'w').write(str(self.n + 1))
69 RenameBreakpoint('rename')