Bug 1054112 - Convert pushlog hook tests into .t test; r=edmorley
authorGregory Szorc <gps@mozilla.com>
Thu, 14 Aug 2014 20:43:34 -0700
changeset 919 e4c22c0819a2
parent 918 7f4e9b9b2783
child 920 4fbca8878852
push id129
push usergszorc@mozilla.com
push dateFri, 15 Aug 2014 17:47:15 +0000
treeherderversion-control-tools@6f1da8433d97 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedmorley
bugs1054112
Bug 1054112 - Convert pushlog hook tests into .t test; r=edmorley runtests.py output before and after conversion: Ran 49 tests in 8.642s Ran 43 tests in 3.171s The pushlog tests are now run concurrently with other tests since the Mercurial test harness can do that, subsequently speeding up test execution.
hghooks/runtests.py
hghooks/tests/common.sh
hghooks/tests/dumppushlog.py
hghooks/tests/test-pushlog-push.t
--- a/hghooks/runtests.py
+++ b/hghooks/runtests.py
@@ -54,161 +54,16 @@ def editFile(filename, original, updated
     for line in lines:
         if line == original:
             newlines.append(updated)
         else:
             newlines.append(line)
   with open(filename, 'a') as f:
     f.write(''.join(newlines))
 
-def getPushesFromDB(repo):
-  conn = sqlite.connect(join(repo.root, '.hg', 'pushlog2.db'))
-  res = conn.execute("SELECT id, user, date, rev, node from pushlog INNER JOIN changesets on pushlog.id = changesets.pushid ORDER BY id")
-  s = set()
-  pushes = []
-  for row in res.fetchall():
-    if row[0] not in s:
-      pushes.append({'id':row[0],
-                     'user':row[1],
-                     'date':row[2],
-                     'changes':[]})
-      s.add(row[0])
-    pushes[-1]['changes'].append({'rev':row[3], 'node':row[4]})
-  return pushes
-
-class TestPushlogHook(unittest.TestCase):
-  def setUp(self):
-    self.ui = ui.ui()
-    self.ui.quiet = True
-    self.ui.verbose = False
-    self.repodir = mkdtemp(prefix="hg-test")
-    init(self.ui, dest=self.repodir)
-    addHook(self.repodir, "pushlog.log")
-    self.repo = hg.repository(self.ui, self.repodir)
-    self.clonedir = mkdtemp(prefix="hg-test")
-    clone(self.ui, self.repo, self.clonedir)
-    self.clonerepo = hg.repository(self.ui, self.clonedir)
-
-  def tearDown(self):
-    shutil.rmtree(self.repodir)
-    shutil.rmtree(self.clonedir)
-
-  def testBasic(self):
-    """Push one changeset, sanity check all the data."""
-    u = self.ui
-    appendFile(join(self.clonedir, "testfile"), "checkin 1")
-    add(u, self.clonerepo, join(self.clonedir, "testfile"))
-    commit(u, self.clonerepo, message="checkin 1 bug 12345")
-    start = time()
-    push(u, self.clonerepo, dest=self.repodir)
-    end = time()
-    p = getPushesFromDB(self.repo)
-    self.assertEqual(len(p), 1)
-    self.assertEqual(len(p[0]['changes']), 1)
-    self.assertEqual(p[0]['user'], getuser())
-    # tough to assert exactly
-    self.assert_(p[0]['date'] >= int(start))
-    self.assert_(p[0]['date'] <= int(end))
-    c = p[0]['changes'][0]
-    tip = self.clonerepo.changectx('tip')
-    self.assertEqual(c['rev'], tip.rev())
-    self.assertEqual(c['node'], hex(tip.node()))
-
-  def testTwoPushes(self):
-    """Push two changesets in two pushes, sanity check all the data."""
-    u = self.ui
-    appendFile(join(self.clonedir, "testfile"), "checkin 1")
-    add(u, self.clonerepo, join(self.clonedir, "testfile"))
-    commit(u, self.clonerepo, message="checkin 1 bug 12345")
-    push(u, self.clonerepo, dest=self.repodir)
-
-    appendFile(join(self.clonedir, "testfile"), "checkin 2")
-    commit(u, self.clonerepo, message="checkin 2 bug 23456")
-    push(u, self.clonerepo, dest=self.repodir)
-
-    pushes = getPushesFromDB(self.repo)
-    self.assertEqual(len(pushes), 2)
-    self.assert_(all(len(p['changes']) == 1 for p in pushes))
-    self.assert_(all(p['user'] == getuser() for p in pushes))
-    self.assert_(pushes[0]['date'] <= pushes[1]['date'])
-    self.assert_(pushes[0]['changes'][0]['rev'] <= pushes[1]['changes'][0]['rev'])
-    # check that all the node/rev pairs we recorded match what hg thinks
-    self.assert_(all(self.clonerepo.changectx(c['node']).rev() == c['rev'] for p in pushes for c in p['changes']))
-
-  def testTwoChangesOnePush(self):
-    """Push two changesets in one push, sanity check all the data."""
-    u = self.ui
-    appendFile(join(self.clonedir, "testfile"), "checkin 1")
-    add(u, self.clonerepo, join(self.clonedir, "testfile"))
-    commit(u, self.clonerepo, message="checkin 1 bug 12345")
-    appendFile(join(self.clonedir, "testfile"), "checkin 2")
-    commit(u, self.clonerepo, message="checkin 2 bug 23456")
-    start = time()
-    push(u, self.clonerepo, dest=self.repodir)
-    end = time()
-
-    pushes = getPushesFromDB(self.repo)
-    self.assertEqual(len(pushes), 1)
-    p = pushes[0]
-    self.assertEqual(len(p['changes']), 2)
-    self.assertEqual(p['user'], getuser())
-    self.assert_(p['date'] >= int(start))
-    self.assert_(p['date'] <= int(end))
-    self.assert_(p['changes'][0]['rev'] <= p['changes'][1]['rev'])
-    # check that all the node/rev pairs we recorded match what hg thinks
-    self.assert_(all(self.clonerepo.changectx(c['node']).rev() == c['rev'] for c in p['changes']))
-
-  def testPushlogPermissions(self):
-    """Check that the pushlog db is group writable after pushing."""
-    u = self.ui
-    appendFile(join(self.clonedir, "testfile"), "checkin 1")
-    add(u, self.clonerepo, join(self.clonedir, "testfile"))
-    commit(u, self.clonerepo, message="checkin 1 bug 12345")
-    push(u, self.clonerepo, dest=self.repodir)
-
-    st = os.stat(join(self.repodir, ".hg", "pushlog2.db"))
-    self.assertEqual(st.st_mode & stat.S_IWGRP, stat.S_IWGRP)
-
-  def testEmptyDB(self):
-    """bug 466149 - Check that pushing to a db without a schema succeeds."""
-    u = self.ui
-    # empty the db file
-    with open(join(self.repodir, ".hg", "pushlog2.db"), 'w') as f:
-      pass
-    appendFile(join(self.clonedir, "testfile"), "checkin 1")
-    add(u, self.clonerepo, join(self.clonedir, "testfile"))
-    commit(u, self.clonerepo, message="checkin 1 bug 12345")
-    push(u, self.clonerepo, dest=self.repodir)
-
-    p = getPushesFromDB(self.repo)
-    self.assertEqual(len(p), 1)
-    self.assertEqual(len(p[0]['changes']), 1)
-
-  def testDBLocking(self):
-    """bug 508863 - Lock the DB and try to push, check that the error doesn't suck so much."""
-    u = self.ui
-    appendFile(join(self.clonedir, "testfile"), "checkin 1")
-    add(u, self.clonerepo, join(self.clonedir, "testfile"))
-    commit(u, self.clonerepo, message="checkin 1 bug 12345")
-    push(u, self.clonerepo, dest=self.repodir)
-
-    # open the repo and insert something to lock it
-    conn = sqlite.connect(join(self.repo.root, '.hg', 'pushlog2.db'))
-    conn.execute("INSERT INTO pushlog (user, date) VALUES('user', 0)")
-
-    appendFile(join(self.clonedir, "testfile"), "checkin 2")
-    commit(u, self.clonerepo, message="checkin 2 bug 23456")
-    sawError = False
-    #TODO: would be nice if we could lower the timeout
-    self.assertRaises(util.Abort, push, u, self.clonerepo, dest=self.repodir)
-    conn.commit()
-    # this one should succeed
-    push(u, self.clonerepo, dest=self.repodir)
-    conn.close()
-
 class ClosureHookTestHelpers:
   """A mixin that provides a director class so we can intercept urlopen and
      change the result for our tests."""
   def setUp(self):
     # add a urllib OpenerDirector so we can intercept urlopen
     class MyDirector:
       expected = []
       opened = 0
new file mode 100644
--- /dev/null
+++ b/hghooks/tests/common.sh
@@ -0,0 +1,11 @@
+configurepushlog () {
+  cat >> $1/.hg/hgrc << EOF
+[hooks]
+pretxnchangegroup.pushlog = python:mozhghooks.pushlog.log
+EOF
+
+}
+
+dumppushlog () {
+  $TESTDIR/hghooks/tests/dumppushlog.py $TESTTMP/$1
+}
new file mode 100755
--- /dev/null
+++ b/hghooks/tests/dumppushlog.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python
+
+# Script to dump the contents of the pushlog db for a repo.
+
+import os
+import sqlite3
+import sys
+
+repo = sys.argv[1]
+dbpath = os.path.join(repo, '.hg', 'pushlog2.db')
+
+if not os.path.exists(dbpath):
+    print('pushlog database does not exist: %s' % dbpath)
+    sys.exit(1)
+
+conn = sqlite3.connect(dbpath)
+res = conn.execute('SELECT id, user, date, rev, node FROM pushlog '
+    'INNER JOIN changesets on pushlog.id = changesets.pushid ORDER BY id')
+
+lastdate = None
+for pid, user, date, rev, node in res.fetchall():
+    if lastdate:
+        assert date >= lastdate
+
+    lastdate = date
+
+    print('ID: %d; user: %s; Date: %s; Rev: %d; Node: %s' % (
+        pid, user, date, rev, node))
new file mode 100644
--- /dev/null
+++ b/hghooks/tests/test-pushlog-push.t
@@ -0,0 +1,165 @@
+  $ . $TESTDIR/hghooks/tests/common.sh
+  $ hg init server
+  $ configurepushlog server
+
+  $ hg init client
+  $ cd client
+  $ dumppushlog server
+  pushlog database does not exist: $TESTTMP/server/.hg/pushlog2.db
+  [1]
+
+Pushing single changesets at a time works
+
+  $ export USER=hguser
+  $ touch foo
+  $ hg commit -A -m 'Add foo'
+  adding foo
+  $ hg log
+  changeset:   0:12cb2e907074
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     Add foo
+  
+  $ hg push ../server
+  pushing to ../server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  Trying to insert into pushlog.
+  Please do not interrupt...
+  Inserted into the pushlog db successfully.
+
+  $ dumppushlog server
+  ID: 1; user: hguser; Date: \d+; Rev: 0; Node: 12cb2e907074dd3f8a985a0bb3713836bae731d8 (re)
+
+  $ echo '2' > foo
+  $ hg commit -m 'Update foo'
+  $ hg push ../server
+  pushing to ../server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  Trying to insert into pushlog.
+  Please do not interrupt...
+  Inserted into the pushlog db successfully.
+
+  $ dumppushlog server
+  ID: 1; user: hguser; Date: \d+; Rev: 0; Node: 12cb2e907074dd3f8a985a0bb3713836bae731d8 (re)
+  ID: 2; user: hguser; Date: \d+; Rev: 1; Node: 6e7d3c626e4989d83a04858aa53fb650d828ab23 (re)
+
+Verify the pushlog database is group writable after pushing
+
+  >>> import os, stat
+  >>> st = os.stat('../server/.hg/pushlog2.db')
+  >>> assert st.st_mode & stat.S_IWGRP == stat.S_IWGRP
+
+Pushing multiple changesets at a time works
+
+  $ echo '3' > foo
+  $ hg commit -m '3'
+  $ echo '4' > foo
+  $ hg commit -m '4'
+  $ hg push ../server
+  pushing to ../server
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 2 changesets with 2 changes to 1 files
+  Trying to insert into pushlog.
+  Please do not interrupt...
+  Inserted into the pushlog db successfully.
+
+  $ dumppushlog server
+  ID: 1; user: hguser; Date: \d+; Rev: 0; Node: 12cb2e907074dd3f8a985a0bb3713836bae731d8 (re)
+  ID: 2; user: hguser; Date: \d+; Rev: 1; Node: 6e7d3c626e4989d83a04858aa53fb650d828ab23 (re)
+  ID: 3; user: hguser; Date: \d+; Rev: 2; Node: 5276547e6f081e8aabd9d49852587caaa54a19b6 (re)
+  ID: 3; user: hguser; Date: \d+; Rev: 3; Node: 241ebd3a5ff9e76aed375695521d83dbfa2531e2 (re)
+
+Multiple users are recognized
+
+  $ hg init ../users
+  $ configurepushlog ../users
+  $ hg push -r 1 ../users >/dev/null
+  $ export USER=another
+  $ hg push ../users >/dev/null
+  $ dumppushlog users
+  ID: 1; user: hguser; Date: \d+; Rev: 0; Node: 12cb2e907074dd3f8a985a0bb3713836bae731d8 (re)
+  ID: 1; user: hguser; Date: \d+; Rev: 1; Node: 6e7d3c626e4989d83a04858aa53fb650d828ab23 (re)
+  ID: 2; user: another; Date: \d+; Rev: 2; Node: 5276547e6f081e8aabd9d49852587caaa54a19b6 (re)
+  ID: 2; user: another; Date: \d+; Rev: 3; Node: 241ebd3a5ff9e76aed375695521d83dbfa2531e2 (re)
+  $ export USER=hguser
+
+Pushing to an empty db file works (bug 466149)
+
+  $ hg init ../empty
+  $ configurepushlog ../empty
+  $ touch ../empty/.hg/pushlog2.db
+  $ hg push ../empty
+  pushing to ../empty
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 4 changesets with 4 changes to 1 files
+  Trying to insert into pushlog.
+  Please do not interrupt...
+  Inserted into the pushlog db successfully.
+
+  $ dumppushlog empty
+  ID: 1; user: hguser; Date: \d+; Rev: 0; Node: 12cb2e907074dd3f8a985a0bb3713836bae731d8 (re)
+  ID: 1; user: hguser; Date: \d+; Rev: 1; Node: 6e7d3c626e4989d83a04858aa53fb650d828ab23 (re)
+  ID: 1; user: hguser; Date: \d+; Rev: 2; Node: 5276547e6f081e8aabd9d49852587caaa54a19b6 (re)
+  ID: 1; user: hguser; Date: \d+; Rev: 3; Node: 241ebd3a5ff9e76aed375695521d83dbfa2531e2 (re)
+
+Pushing to a locked DB errors out (bug 508863)
+
+  $ cat >> lockdb.py << EOF
+  > import os, sqlite3, sys, time
+  > conn = sqlite3.connect(sys.argv[1])
+  > conn.execute('INSERT INTO pushlog (user, date) VALUES("user", 0)')
+  > while not os.path.exists(sys.argv[2]):
+  >    time.sleep(0.1)
+  > EOF
+
+  $ hg init ../locked
+  $ configurepushlog ../locked
+  $ hg push -r 0 ../locked >/dev/null
+  $ python lockdb.py ../locked/.hg/pushlog2.db unlock &
+  $ pid=$!
+  $ echo $pid >> $DAEMON_PIDS
+  $ hg push ../locked
+  pushing to ../locked
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 3 changesets with 3 changes to 1 files
+  Trying to insert into pushlog.
+  Please do not interrupt...
+  Pushlog database is locked. Please retry your push.
+  transaction abort!
+  rollback completed
+  abort: pretxnchangegroup.pushlog hook failed
+  [255]
+  $ touch unlock
+
+  $ hg push -r 1 ../locked
+  pushing to ../locked
+  searching for changes
+  adding changesets
+  adding manifests
+  adding file changes
+  added 1 changesets with 1 changes to 1 files
+  Trying to insert into pushlog.
+  Please do not interrupt...
+  Inserted into the pushlog db successfully.
+
+  $ dumppushlog locked
+  ID: 1; user: hguser; Date: \d+; Rev: 0; Node: 12cb2e907074dd3f8a985a0bb3713836bae731d8 (re)
+  ID: 2; user: hguser; Date: \d+; Rev: 1; Node: 6e7d3c626e4989d83a04858aa53fb650d828ab23 (re)