[PATCH] test: Port atomicity test to Python
authorAustin Clements <aclements@csail.mit.edu>
Fri, 3 Oct 2014 16:58:03 +0000 (12:58 +2000)
committerW. Trevor King <wking@tremily.us>
Fri, 7 Nov 2014 18:04:56 +0000 (10:04 -0800)
01/316ad41c5f139cd451eb724884830106815bbf [new file with mode: 0644]

diff --git a/01/316ad41c5f139cd451eb724884830106815bbf b/01/316ad41c5f139cd451eb724884830106815bbf
new file mode 100644 (file)
index 0000000..3377401
--- /dev/null
@@ -0,0 +1,247 @@
+Return-Path: <aclements@csail.mit.edu>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+       by olra.theworths.org (Postfix) with ESMTP id 15AAB431FBC\r
+       for <notmuch@notmuchmail.org>; Fri,  3 Oct 2014 09:58:36 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: -2.3\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=-2.3 tagged_above=-999 required=5\r
+       tests=[RCVD_IN_DNSWL_MED=-2.3] autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+       by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+       with ESMTP id QmaXSL60CxpO for <notmuch@notmuchmail.org>;\r
+       Fri,  3 Oct 2014 09:58:29 -0700 (PDT)\r
+Received: from dmz-mailsec-scanner-2.mit.edu (dmz-mailsec-scanner-2.mit.edu\r
+       [18.9.25.13])\r
+       (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))\r
+       (No client certificate requested)\r
+       by olra.theworths.org (Postfix) with ESMTPS id 59798431FB6\r
+       for <notmuch@notmuchmail.org>; Fri,  3 Oct 2014 09:58:29 -0700 (PDT)\r
+X-AuditID: 1209190d-f79c06d000006f95-80-542ed5b40568\r
+Received: from mailhub-auth-1.mit.edu ( [18.9.21.35])\r
+       (using TLS with cipher AES256-SHA (256/256 bits))\r
+       (Client did not present a certificate)\r
+       by dmz-mailsec-scanner-2.mit.edu (Symantec Messaging Gateway) with SMTP\r
+       id 7E.EA.28565.4B5DE245; Fri,  3 Oct 2014 12:58:28 -0400 (EDT)\r
+Received: from outgoing.mit.edu (outgoing-auth-1.mit.edu [18.9.28.11])\r
+       by mailhub-auth-1.mit.edu (8.13.8/8.9.2) with ESMTP id s93GwQhN028669; \r
+       Fri, 3 Oct 2014 12:58:26 -0400\r
+Received: from drake.dyndns.org\r
+       (static-155-212-141-65.mas.onecommunications.net [155.212.141.65])\r
+       (authenticated bits=0)\r
+       (User authenticated as amdragon@ATHENA.MIT.EDU)\r
+       by outgoing.mit.edu (8.13.8/8.12.4) with ESMTP id s93GwEBP019243\r
+       (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=NOT);\r
+       Fri, 3 Oct 2014 12:58:24 -0400\r
+Received: from amthrax by drake.dyndns.org with local (Exim 4.84)\r
+       (envelope-from <aclements@csail.mit.edu>)\r
+       id 1Xa6BJ-00022m-AR; Fri, 03 Oct 2014 12:58:13 -0400\r
+From: Austin Clements <aclements@csail.mit.edu>\r
+To: notmuch@notmuchmail.org\r
+Subject: [PATCH] test: Port atomicity test to Python\r
+Date: Fri,  3 Oct 2014 12:58:03 -0400\r
+Message-Id: <1412355483-7670-1-git-send-email-aclements@csail.mit.edu>\r
+X-Mailer: git-send-email 2.1.0\r
+X-Brightmail-Tracker:\r
+ H4sIAAAAAAAAA+NgFlrLIsWRmVeSWpSXmKPExsUixCmqrLvlql6IwYIlahZT1jxmtbh+cyaz\r
+       A5PHkdeb2TyerbrFHMAUxWWTkpqTWZZapG+XwJXRO1+3YK9JxcnWJawNjJs1uxg5OCQETCSm\r
+       H5TtYuQEMsUkLtxbzwZiCwnMZpK4cjSni5ELyN7AKNHzeB8bhHOdSWLm7EWMEM4SRonJ+zYw\r
+       g7SwCehLrFg7iRXEFhGQlth5dzaYzSzgLPHw80Y2kG3CQNv2vVcHCbMIqEpsutDJCBLmFXCT\r
+       uPsgD+IIOYkNu/8zTmDkXcDIsIpRNiW3Sjc3MTOnODVZtzg5MS8vtUjXSC83s0QvNaV0EyM4\r
+       JCR5dzC+O6h0iFGAg1GJh/fDDd0QIdbEsuLK3EOMkhxMSqK8sVf0QoT4kvJTKjMSizPii0pz\r
+       UosPMUpwMCuJ8C5YCZTjTUmsrEotyodJSXOwKInzbvrBFyIkkJ5YkpqdmlqQWgSTleHgUJLg\r
+       LQUZKliUmp5akZaZU4KQZuLgBBnOAzQ8HaSGt7ggMbc4Mx0if4pRl2PSxve9TEIsefl5qVLi\r
+       vIsuAxUJgBRllObBzYHF8itGcaC3hHnzQUbxANMA3KRXQEuYgJa8s9cFWVKSiJCSamDMuJsr\r
+       bRp+TGrdofwLgdka97edEE3YeulqjXbsrmei78z/tb35rTxPRu8Y0yqhyc9LcpLNv7P9YSvR\r
+       yqhYsl5TzHeHcdheDkmRRzONf969L7b7qmVPf43uv63h2yd5fJzz3PK7rz1bCWPCxwsdPtf0\r
+       E4t+cLrUVc15frXfac+FyBLubYfOz2VWYinOSDTUYi4qTgQAc5E+acACAAA=\r
+Cc: Austin Clements <aclements@csail.mit.edu>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+       <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+       <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Fri, 03 Oct 2014 16:58:36 -0000\r
+\r
+Previously, this was implemented using a horrible GDB script (because\r
+there is no such thing as a non-horrible GDB script).  This GDB script\r
+often broke with newer versions of GDB for mysterious reasons.  Port\r
+the test script to GDB's Python API, which makes the code much cleaner\r
+and, hopefully, more stable.\r
+---\r
+\r
+Hi Amadeusz.  Does this patch fix the problem for you?  I don't have\r
+GDB 7.8, so I can't test against it, but the Python interface is less\r
+fragile than the GDB scripting language.  (Even if this doesn't fix\r
+your problem, I think we should switch to the Python interface.)\r
+\r
+ test/T380-atomicity.sh |  2 +-\r
+ test/atomicity.gdb     | 54 --------------------------------------\r
+ test/atomicity.py      | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++\r
+ 3 files changed, 72 insertions(+), 55 deletions(-)\r
+ delete mode 100644 test/atomicity.gdb\r
+ create mode 100644 test/atomicity.py\r
+\r
+diff --git a/test/T380-atomicity.sh b/test/T380-atomicity.sh\r
+index 2daef90..ee1e2f4 100755\r
+--- a/test/T380-atomicity.sh\r
++++ b/test/T380-atomicity.sh\r
+@@ -64,7 +64,7 @@ if test_require_external_prereq gdb; then\r
+     # -tty /dev/null works around a conflict between the 'timeout' wrapper\r
+     # and gdb's attempt to control the TTY.\r
+     export MAIL_DIR\r
+-    gdb -tty /dev/null -batch -x $TEST_DIRECTORY/atomicity.gdb notmuch 1>gdb.out 2>&1\r
++    gdb -tty /dev/null -batch -x $TEST_DIRECTORY/atomicity.py notmuch 1>gdb.out 2>&1\r
\r
+     # Get the final, golden output\r
+     notmuch search '*' > expected\r
+diff --git a/test/atomicity.gdb b/test/atomicity.gdb\r
+deleted file mode 100644\r
+index 15adb16..0000000\r
+--- a/test/atomicity.gdb\r
++++ /dev/null\r
+@@ -1,54 +0,0 @@\r
+-# This gdb script runs notmuch new and simulates killing and\r
+-# restarting notmuch new after every Xapian commit.  To simulate this\r
+-# more efficiently, this script runs notmuch new and, immediately\r
+-# after every Xapian commit, it *pauses* the running notmuch new,\r
+-# copies the entire database and maildir to a snapshot directory, and\r
+-# executes a full notmuch new on that snapshot, comparing the final\r
+-# results with the expected output.  It can then resume the paused\r
+-# notmuch new, which is still running on the original maildir, and\r
+-# repeat this process.\r
+-\r
+-set args new\r
+-\r
+-# Make Xapian commit after every operation instead of batching\r
+-set environment XAPIAN_FLUSH_THRESHOLD = 1\r
+-\r
+-# gdb can't keep track of a simple integer.  This is me weeping.\r
+-shell echo 0 > outcount\r
+-\r
+-shell touch inodes\r
+-\r
+-# work around apparent issue with lazy library loading on some\r
+-# platforms\r
+-set breakpoint pending on\r
+-\r
+-break rename\r
+-commands\r
+-# As an optimization, only consider snapshots after a Xapian commit.\r
+-# Xapian overwrites record.base? as the last step in the commit.\r
+-shell echo > gdbcmd\r
+-shell stat -c %i $MAIL_DIR/.notmuch/xapian/record.base* > inodes.new\r
+-shell if cmp inodes inodes.new; then echo cont > gdbcmd; fi\r
+-shell mv inodes.new inodes\r
+-source gdbcmd\r
+-\r
+-# Save a backtrace in case the test does fail\r
+-set logging file backtrace\r
+-set logging on\r
+-backtrace\r
+-set logging off\r
+-shell mv backtrace backtrace.`cat outcount`\r
+-\r
+-# Snapshot the database\r
+-shell rm -r $MAIL_DIR.snap/.notmuch\r
+-shell cp -r $MAIL_DIR/.notmuch $MAIL_DIR.snap/.notmuch\r
+-# Restore the mtime of $MAIL_DIR.snap, which we just changed\r
+-shell touch -r $MAIL_DIR $MAIL_DIR.snap\r
+-# Run notmuch new to completion on the snapshot\r
+-shell NOTMUCH_CONFIG=${NOTMUCH_CONFIG}.snap XAPIAN_FLUSH_THRESHOLD=1000 notmuch new > /dev/null\r
+-shell NOTMUCH_CONFIG=${NOTMUCH_CONFIG}.snap notmuch search '*' > search.`cat outcount` 2>&1\r
+-shell echo $(expr $(cat outcount) + 1) > outcount\r
+-cont\r
+-end\r
+-\r
+-run\r
+diff --git a/test/atomicity.py b/test/atomicity.py\r
+new file mode 100644\r
+index 0000000..01a4205\r
+--- /dev/null\r
++++ b/test/atomicity.py\r
+@@ -0,0 +1,71 @@\r
++# This gdb Python script runs notmuch new and simulates killing and\r
++# restarting notmuch new after every Xapian commit.  To simulate this\r
++# more efficiently, this script runs notmuch new and, immediately\r
++# after every Xapian commit, it *pauses* the running notmuch new,\r
++# copies the entire database and maildir to a snapshot directory, and\r
++# executes a full notmuch new on that snapshot, comparing the final\r
++# results with the expected output.  It can then resume the paused\r
++# notmuch new, which is still running on the original maildir, and\r
++# repeat this process.\r
++\r
++import gdb\r
++import os\r
++import glob\r
++import shutil\r
++import subprocess\r
++\r
++gdb.execute('set args new')\r
++\r
++# Make Xapian commit after every operation instead of batching\r
++gdb.execute('set environment XAPIAN_FLUSH_THRESHOLD = 1')\r
++\r
++maildir = os.environ['MAIL_DIR']\r
++\r
++# Trap calls to rename, which happens just before Xapian commits\r
++class RenameBreakpoint(gdb.Breakpoint):\r
++    def __init__(self, *args, **kwargs):\r
++        super(RenameBreakpoint, self).__init__(*args, **kwargs)\r
++        self.last_inodes = {}\r
++        self.n = 0\r
++\r
++    def stop(self):\r
++        # As an optimization, only consider snapshots after a Xapian\r
++        # has really committed.  Xapian overwrites record.base? as the\r
++        # last step in the commit, so keep an eye on their inumbers.\r
++        inodes = {}\r
++        for path in glob.glob('%s/.notmuch/xapian/record.base*' % maildir):\r
++            inodes[path] = os.stat(path).st_ino\r
++        if inodes == self.last_inodes:\r
++            # Continue\r
++            return False\r
++        self.last_inodes = inodes\r
++\r
++        # Save a backtrace in case the test does fail\r
++        backtrace = gdb.execute('backtrace', to_string=True)\r
++        open('backtrace.%d' % self.n, 'w').write(backtrace)\r
++\r
++        # Snapshot the database\r
++        shutil.rmtree('%s.snap/.notmuch' % maildir)\r
++        shutil.copytree('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)\r
++        # Restore the mtime of $MAIL_DIR.snap/\r
++        shutil.copystat('%s/.notmuch' % maildir, '%s.snap/.notmuch' % maildir)\r
++\r
++        # Run notmuch new to completion on the snapshot\r
++        env = os.environ.copy()\r
++        env.update(NOTMUCH_CONFIG=os.environ['NOTMUCH_CONFIG'] + '.snap',\r
++                   XAPIAN_FLUSH_THRESHOLD='1000')\r
++        subprocess.check_call(\r
++            ['notmuch', 'new'], env=env, stdout=open('/dev/null', 'w'))\r
++        subprocess.check_call(\r
++            ['notmuch', 'search', '*'], env=env,\r
++            stdout=open('search.%d' % self.n, 'w'))\r
++\r
++        # Tell the shell how far we've gotten\r
++        open('outcount', 'w').write(str(self.n + 1))\r
++\r
++        # Continue\r
++        self.n += 1\r
++        return False\r
++RenameBreakpoint('rename')\r
++\r
++gdb.execute('run')\r
+-- \r
+2.1.0\r
+\r