wireprotov2: decode responses to their expected types
authorGregory Szorc <gregory.szorc@gmail.com>
Sat, 14 Apr 2018 11:49:06 -0700
changeset 37721 f7673845b167
parent 37720 d715a85003c8
child 37722 89a16704114c
wireprotov2: decode responses to their expected types Callers of established wire protocol commands expect the response from that command to be decoded into a data structure. It's not very useful if callers get back a stream of bytes and don't know how they should be interpreted - especially since that stream of bytes varies by wire protocol and even the transport within that protocol version. This commit establishes decoding functions for various command responses so callers of those commands get the response type they expect. In theory, this should make the version 2 HTTP peer usable for various operations. But I haven't tested to confirm. Differential Revision: https://phab.mercurial-scm.org/D3381
mercurial/wireprotov2peer.py
tests/test-wireproto-command-branchmap.t
tests/test-wireproto-command-heads.t
tests/test-wireproto-command-known.t
tests/test-wireproto-command-listkeys.t
tests/test-wireproto-command-lookup.t
tests/test-wireproto-command-pushkey.t
--- a/mercurial/wireprotov2peer.py	Sat Apr 14 11:46:08 2018 -0700
+++ b/mercurial/wireprotov2peer.py	Sat Apr 14 11:49:06 2018 -0700
@@ -12,6 +12,7 @@
     cbor,
 )
 from . import (
+    encoding,
     error,
     util,
     wireprotoframing,
@@ -127,7 +128,13 @@
                 response.cbor = True
 
             if meta['eos']:
-                self._futures[frame.requestid].set_result(response)
+                # If the command has a decoder, resolve the future to the
+                # decoded value. Otherwise resolve to the rich response object.
+                decoder = COMMAND_DECODERS.get(response.command)
+
+                result = decoder(response) if decoder else response
+
+                self._futures[frame.requestid].set_result(result)
 
                 del self._requests[frame.requestid]
                 del self._futures[frame.requestid]
@@ -135,3 +142,38 @@
         else:
             raise error.ProgrammingError(
                 'unhandled action from clientreactor: %s' % action)
+
+def decodebranchmap(resp):
+    # Response should be a single CBOR map of branch name to array of nodes.
+    bm = next(resp.cborobjects())
+
+    return {encoding.tolocal(k): v for k, v in bm.items()}
+
+def decodeheads(resp):
+    # Array of node bytestrings.
+    return next(resp.cborobjects())
+
+def decodeknown(resp):
+    # Bytestring where each byte is a 0 or 1.
+    raw = next(resp.cborobjects())
+
+    return [True if c == '1' else False for c in raw]
+
+def decodelistkeys(resp):
+    # Map with bytestring keys and values.
+    return next(resp.cborobjects())
+
+def decodelookup(resp):
+    return next(resp.cborobjects())
+
+def decodepushkey(resp):
+    return next(resp.cborobjects())
+
+COMMAND_DECODERS = {
+    'branchmap': decodebranchmap,
+    'heads': decodeheads,
+    'known': decodeknown,
+    'listkeys': decodelistkeys,
+    'lookup': decodelookup,
+    'pushkey': decodepushkey,
+}
--- a/tests/test-wireproto-command-branchmap.t	Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-branchmap.t	Sat Apr 14 11:49:06 2018 -0700
@@ -67,6 +67,6 @@
   received frame(size=112; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [{b'branch1': [b'\xb5\xfa\xac\xdf\xd2c7h\xcb1R3l\xc0\x953\x81&f\x88'], b'branch2': [b'"Aa\xc7X\x9a\xa4\x8f\xa8:H\xfe\xff^\x95\xb5j\xe3\'\xfc'], b'default': [b'&\x80Z\xba\x1e`\n\x82\xe96a\x14\x9f#\x13\x86j"\x1a{', b'\xbe\x0e\xf7<\x17\xad\xe3\xfc\x89\xdcAp\x1e\xb9\xfc:\x91\xb5\x82\x82']}]
+  response: {b'branch1': [b'\xb5\xfa\xac\xdf\xd2c7h\xcb1R3l\xc0\x953\x81&f\x88'], b'branch2': [b'"Aa\xc7X\x9a\xa4\x8f\xa8:H\xfe\xff^\x95\xb5j\xe3\'\xfc'], b'default': [b'&\x80Z\xba\x1e`\n\x82\xe96a\x14\x9f#\x13\x86j"\x1a{', b'\xbe\x0e\xf7<\x17\xad\xe3\xfc\x89\xdcAp\x1e\xb9\xfc:\x91\xb5\x82\x82']}
 
   $ cat error.log
--- a/tests/test-wireproto-command-heads.t	Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-heads.t	Sat Apr 14 11:49:06 2018 -0700
@@ -58,7 +58,7 @@
   received frame(size=64; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [[b'\x1dok\x91\xd4J\xab\xa6\xd5\xe5\x80\xbc0\xa9\x94\x850\xdb\xe0\x0b', b'\xaeI.6\xb0\xc83\x9f\xfa\xf3(\xd0\x0b\x85\xb4R]\xe1\x16^', b')Dm-\xc5A\x9c_\x97Dz\x8b\xc0b\xe4\xcc2\x8b\xf2A']]
+  response: [b'\x1dok\x91\xd4J\xab\xa6\xd5\xe5\x80\xbc0\xa9\x94\x850\xdb\xe0\x0b', b'\xaeI.6\xb0\xc83\x9f\xfa\xf3(\xd0\x0b\x85\xb4R]\xe1\x16^', b')Dm-\xc5A\x9c_\x97Dz\x8b\xc0b\xe4\xcc2\x8b\xf2A']
 
 Requesting just the public heads works
 
@@ -91,6 +91,6 @@
   received frame(size=22; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [[b'x\xd2\xdc\xa46\xb2\xf5\xb1\x88\xac&~)\xb8\x1e\x07&m8\xfc']]
+  response: [b'x\xd2\xdc\xa46\xb2\xf5\xb1\x88\xac&~)\xb8\x1e\x07&m8\xfc']
 
   $ cat error.log
--- a/tests/test-wireproto-command-known.t	Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-known.t	Sat Apr 14 11:49:06 2018 -0700
@@ -50,7 +50,7 @@
   received frame(size=1; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [b'']
+  response: []
 
 Single known node works
 
@@ -83,7 +83,7 @@
   received frame(size=2; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [b'1']
+  response: [True]
 
 Multiple nodes works
 
@@ -116,6 +116,6 @@
   received frame(size=4; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [b'101']
+  response: [True, False, True]
 
   $ cat error.log
--- a/tests/test-wireproto-command-listkeys.t	Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-listkeys.t	Sat Apr 14 11:49:06 2018 -0700
@@ -54,7 +54,7 @@
   received frame(size=32; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [{b'bookmarks': b'', b'namespaces': b'', b'phases': b''}]
+  response: {b'bookmarks': b'', b'namespaces': b'', b'phases': b''}
 
 Request for phases works
 
@@ -87,7 +87,7 @@
   received frame(size=61; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [{b'be0ef73c17ade3fc89dc41701eb9fc3a91b58282': b'1', b'publishing': b'True'}]
+  response: {b'be0ef73c17ade3fc89dc41701eb9fc3a91b58282': b'1', b'publishing': b'True'}
 
 Request for bookmarks works
 
@@ -120,6 +120,6 @@
   received frame(size=45; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [{b'@': b'26805aba1e600a82e93661149f2313866a221a7b'}]
+  response: {b'@': b'26805aba1e600a82e93661149f2313866a221a7b'}
 
   $ cat error.log
--- a/tests/test-wireproto-command-lookup.t	Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-lookup.t	Sat Apr 14 11:49:06 2018 -0700
@@ -50,6 +50,6 @@
   received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob)
   s>     0\r\n
   s>     \r\n
-  response: [b'Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0']
+  response: b'Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0'
 
   $ cat error.log
--- a/tests/test-wireproto-command-pushkey.t	Sat Apr 14 11:46:08 2018 -0700
+++ b/tests/test-wireproto-command-pushkey.t	Sat Apr 14 11:49:06 2018 -0700
@@ -53,7 +53,7 @@
   received frame(size=*; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor) (glob)
   s>     0\r\n
   s>     \r\n
-  response: [True]
+  response: True
 
   $ sendhttpv2peer << EOF
   > command listkeys
@@ -84,6 +84,6 @@
   received frame(size=45; request=1; stream=2; streamflags=stream-begin; type=bytes-response; flags=eos|cbor)
   s>     0\r\n
   s>     \r\n
-  response: [{b'@': b'426bada5c67598ca65036d57d9e4b64b0c1ce7a0'}]
+  response: {b'@': b'426bada5c67598ca65036d57d9e4b64b0c1ce7a0'}
 
   $ cat error.log