[PATCH] testing: allow Hypothesis tests to disable extensions

David R. MacIver david at drmaciver.com
Fri Feb 26 17:16:45 UTC 2016


# HG changeset patch
# User David R. MacIver <david at drmaciver.com>
# Date 1456506949 0
#      Fri Feb 26 17:15:49 2016 +0000
# Node ID 9a28035d39f02fc7e03d0d376ce66998628a6877
# Parent  18680fed30581e7286a72b93af97de980a178d96
testing: allow Hypothesis tests to disable extensions

Doing this required the introduction of a mechanism for keeping
track of more general config in the test. At present this is only
used for extensions but it could be used more widely (e.g. to
control specific extension behaviour)

This greatly simplifies the extension management logic by introducing
a general notion of config, which we maintain ourselves and pass to
HG on every invocation.

This results in significantly less error prone test generation, and
also allows us to turn extensions off as well as on.

The logic that used an environment variable to rerun the tests with
an extension disabled now just edits the test file (in a fresh copy)
to remove these --config command line flags.

diff -r 18680fed3058 -r 9a28035d39f0 tests/test-verify-repo-operations.py
--- a/tests/test-verify-repo-operations.py	Wed Feb 24 13:20:06 2016 +0000
+++ b/tests/test-verify-repo-operations.py	Fri Feb 26 17:15:49 2016 +0000
@@ -97,6 +97,8 @@
     lambda s: s.encode('utf-8')
 )
 
+extensions = st.sampled_from(('shelve', 'mq', 'blackbox',))
+
 @contextmanager
 def acceptableerrors(*args):
     """Sometimes we know an operation we're about to perform might fail, and
@@ -151,15 +153,15 @@
         os.chdir(testtmp)
         self.log = []
         self.failed = False
+        self.configperrepo = {}
+        self.all_extensions = set()
+        self.non_skippable_extensions = set()
 
         self.mkdirp("repos")
         self.cd("repos")
         self.mkdirp("repo1")
         self.cd("repo1")
         self.hg("init")
-        self.extensions = {}
-        self.all_extensions = set()
-        self.non_skippable_extensions = set()
 
     def teardown(self):
         """On teardown we clean up after ourselves as usual, but we also
@@ -190,29 +192,32 @@
         e = None
         if not self.failed:
             try:
-                for ext in (
-                    self.all_extensions - self.non_skippable_extensions
-                ):
-                    try:
-                        os.environ["SKIP_EXTENSION"] = ext
-                        output = subprocess.check_output([
-                            runtests, path, "--local",
-                        ], stderr=subprocess.STDOUT)
-                        assert "Ran 1 test" in output, output
-                    finally:
-                        del os.environ["SKIP_EXTENSION"]
                 output = subprocess.check_output([
                     runtests, path, "--local", "--pure"
                 ], stderr=subprocess.STDOUT)
                 assert "Ran 1 test" in output, output
+                for ext in (
+                    self.all_extensions - self.non_skippable_extensions
+                ):
+                    tf = os.path.join(testtmp, "test-generated-no-%s.t" % (
+                        ext,
+                    ))
+                    with open(tf, 'w') as o:
+                        for l in ttest.splitlines():
+                            if l.startswith("  $ hg"):
+                                l = l.replace(
+                                    "--config %s=" % (
+                                        extensionconfigkey(ext),), "")
+                            o.write(l + os.linesep)
+                    with open(tf, 'r') as r:
+                        t = r.read()
+                        assert ext not in t, t
+                    output = subprocess.check_output([
+                        runtests, tf, "--local",
+                    ], stderr=subprocess.STDOUT)
+                    assert "Ran 1 test" in output, output
             except subprocess.CalledProcessError as e:
                 note(e.output)
-            finally:
-                os.unlink(path)
-                try:
-                    os.unlink(path + ".err")
-                except OSError:
-                    pass
         if self.failed or e is not None:
             with open(savefile, "wb") as o:
                 o.write(ttest)
@@ -244,7 +249,11 @@
         self.log.append("$ cd -- %s" % (pipes.quote(path),))
 
     def hg(self, *args):
-        self.command("hg", *args)
+        extra_flags = []
+        for key, value in self.config.items():
+            extra_flags.append("--config")
+            extra_flags.append("%s=%s" % (key, value))
+        self.command("hg", *(tuple(extra_flags) + args))
 
     def command(self, *args):
         self.log.append("$ " + ' '.join(map(pipes.quote, args)))
@@ -384,6 +393,10 @@
     def currentrepo(self):
         return os.path.basename(os.getcwd())
 
+    @property
+    def config(self):
+        return self.configperrepo.setdefault(self.currentrepo, {})
+
     @rule(
         target=repos,
         source=repos,
@@ -486,32 +499,20 @@
 
     # Section: Extension management
     def hasextension(self, extension):
-        repo = self.currentrepo
-        return repo in self.extensions and extension in self.extensions[repo]
+        return extensionconfigkey(extension) in self.config
 
     def commandused(self, extension):
         assert extension in self.all_extensions
         self.non_skippable_extensions.add(extension)
 
-    @rule(extension=st.sampled_from((
-        'shelve', 'mq', 'blackbox',
-    )))
+    @rule(extension=extensions)
     def addextension(self, extension):
         self.all_extensions.add(extension)
-        extensions = self.extensions.setdefault(self.currentrepo, set())
-        if extension in extensions:
-            return
-        extensions.add(extension)
-        if not os.path.exists(hgrc):
-            self.command("touch", hgrc)
-        with open(hgrc, 'a') as o:
-            line = "[extensions]\n%s=\n" % (extension,)
-            o.write(line)
-        for l in line.splitlines():
-            self.log.append((
-                '$ if test "$SKIP_EXTENSION" != "%s" ; '
-                'then echo %r >> %s; fi') % (
-                    extension, l, hgrc,))
+        self.config[extensionconfigkey(extension)] = ""
+
+    @rule(extension=extensions)
+    def removeextension(self, extension):
+        self.config.pop(extensionconfigkey(extension), None)
 
     # Section: Commands from the shelve extension
     @rule()
@@ -545,6 +546,9 @@
     def close(self):
         self.underlying.close()
 
+def extensionconfigkey(extension):
+    return "extensions." + extension
+
 settings.register_profile(
     'default',  settings(
         timeout=300,


More information about the Mercurial-devel mailing list