changeset 39666:d8f07b16abfc

phabricator: add support for using the vcr library to mock interactions I'll use this in an upcoming test. The decorator dancing in this is more complicated than I'd like, but it beats repeating all this code everywhere. Differential Revision: https://phab.mercurial-scm.org/D4600
author Augie Fackler <raf@durin42.com>
date Sat, 15 Sep 2018 00:20:03 -0400
parents d6d094259d9c
children a641fd1a1196
files contrib/phabricator.py
diffstat 1 files changed, 35 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/contrib/phabricator.py	Sat Sep 15 00:19:09 2018 -0400
+++ b/contrib/phabricator.py	Sat Sep 15 00:20:03 2018 -0400
@@ -106,6 +106,37 @@
     b'phabricator.node': b'',
 }
 
+_VCR_FLAGS = [
+    (b'', b'test-vcr', b'',
+     _(b'Path to a vcr file. If nonexistent, will record a new vcr transcript'
+       b', otherwise will mock all http requests using the specified vcr file.'
+       b' (ADVANCED)'
+     )),
+]
+
+def vcrcommand(name, flags, spec):
+    fullflags = flags + _VCR_FLAGS
+    def decorate(fn):
+        def inner(*args, **kwargs):
+            cassette = kwargs.pop(r'test_vcr', None)
+            if cassette:
+                import hgdemandimport
+                with hgdemandimport.deactivated():
+                    import vcr as vcrmod
+                    import vcr.stubs as stubs
+                vcr = vcrmod.VCR(
+                    serializer=r'json',
+                    custom_patches=[
+                        (urlmod, 'httpconnection', stubs.VCRHTTPConnection),
+                        (urlmod, 'httpsconnection', stubs.VCRHTTPSConnection),
+                    ])
+                with vcr.use_cassette(cassette):
+                    return fn(*args, **kwargs)
+            return fn(*args, **kwargs)
+        inner.__name__ = fn.__name__
+        return command(name, fullflags, spec)(inner)
+    return decorate
+
 def urlencodenested(params):
     """like urlencode, but works with nested parameters.
 
@@ -215,7 +246,7 @@
         raise error.Abort(msg)
     return parsed[r'result']
 
-@command(b'debugcallconduit', [], _(b'METHOD'))
+@vcrcommand(b'debugcallconduit', [], _(b'METHOD'))
 def debugcallconduit(ui, repo, name):
     """call Conduit API
 
@@ -452,7 +483,7 @@
                           % b' '.join(sorted(unresolved)))
     return [entry[r'phid'] for entry in data]
 
-@command(b'phabsend',
+@vcrcommand(b'phabsend',
          [(b'r', b'rev', [], _(b'revisions to send'), _(b'REV')),
           (b'', b'amend', True, _(b'update commit messages')),
           (b'', b'reviewer', [], _(b'specify reviewers')),
@@ -909,7 +940,7 @@
         content = b'%s%s\n%s' % (header, desc, body)
         write(encoding.unitolocal(content))
 
-@command(b'phabread',
+@vcrcommand(b'phabread',
          [(b'', b'stack', False, _(b'read dependencies'))],
          _(b'DREVSPEC [OPTIONS]'))
 def phabread(ui, repo, spec, **opts):
@@ -936,7 +967,7 @@
     drevs = querydrev(repo, spec)
     readpatch(repo, drevs, ui.write)
 
-@command(b'phabupdate',
+@vcrcommand(b'phabupdate',
          [(b'', b'accept', False, _(b'accept revisions')),
           (b'', b'reject', False, _(b'reject revisions')),
           (b'', b'abandon', False, _(b'abandon revisions')),