Patchwork D10753: persistent-nodemap: add a way to make the picked uid predictable

login
register
mail settings
Submitter phabricator
Date May 20, 2021, 2:19 p.m.
Message ID <differential-rev-PHID-DREV-yzj3exkmudh2twsuwt5m-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/49074/
State Superseded
Headers show

Comments

phabricator - May 20, 2021, 2:19 p.m.
marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  This will make the test less volatile and therefore easier to maintain. I am
  setting this is for the persistent nodemap docket first, but my target is to use
  similar logic for the revlogv2 (and co) test.
  
  For persisent nodemap, they are too many different in how each test variants (with rust, without rust, etc) needs new uid for this be really useful (right now). However it will be directly useful for the revlogv2 logic.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D10753

AFFECTED FILES
  mercurial/revlogutils/nodemap.py
  tests/run-tests.py

CHANGE DETAILS




To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/tests/run-tests.py b/tests/run-tests.py
--- a/tests/run-tests.py
+++ b/tests/run-tests.py
@@ -1376,6 +1376,8 @@ 
         env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase') or ''
         env['HGEMITWARNINGS'] = '1'
         env['TESTTMP'] = _bytes2sys(self._testtmp)
+        docket_id_file = os.path.join(_bytes2sys(self._testtmp), 'DOCKETID')
+        env['HGTEST_DOCKETIDFILE'] = docket_id_file
         env['TESTNAME'] = self.name
         env['HOME'] = _bytes2sys(self._testtmp)
         if os.name == 'nt':
diff --git a/mercurial/revlogutils/nodemap.py b/mercurial/revlogutils/nodemap.py
--- a/mercurial/revlogutils/nodemap.py
+++ b/mercurial/revlogutils/nodemap.py
@@ -10,13 +10,16 @@ 
 
 import errno
 import os
+import random
 import re
 import struct
 
 from ..node import hex
 
 from .. import (
+    encoding,
     error,
+    pycompat,
     util,
 )
 
@@ -288,6 +291,45 @@ 
     return hex(os.urandom(ID_SIZE))
 
 
+# some special test logic to avoid anoying random output in the test
+stable_docket_file = encoding.environ.get(b'HGTEST_DOCKETIDFILE')
+
+if stable_docket_file:
+
+    def _make_uid():
+        try:
+            with open(stable_docket_file, mode='rb') as f:
+                seed = f.read().strip()
+        except IOError as inst:
+            if inst.errno != errno.ENOENT:
+                raise
+            seed = b'4'  # chosen by a fair dice roll. garanteed to be random
+        if pycompat.ispy3:
+            iter_seed = iter(seed)
+        else:
+            iter_seed = (ord(c) for c in seed)
+        # some basic circular sum hashing on 64 bits
+        int_seed = 0
+        low_mask = int('1' * 35, 2)
+        for i in iter_seed:
+            high_part = int_seed >> 35
+            low_part = (int_seed & low_mask) << 28
+            int_seed = high_part + low_part + i
+        r = random.Random()
+        if pycompat.ispy3:
+            r.seed(int_seed, version=1)
+        else:
+            r.seed(int_seed)
+        # once we drop python 3.8 support we can simply use r.randbytes
+        raw = r.getrandbits(ID_SIZE * 8)
+        assert ID_SIZE == 8
+        p = struct.pack('>Q', raw)
+        new = hex(p)
+        with open(stable_docket_file, 'wb') as f:
+            f.write(new)
+        return new
+
+
 class NodeMapDocket(object):
     """metadata associated with persistent nodemap data