exchangev2: remove it
authorRaphaël Gomès <rgomes@octobus.net>
Tue, 07 Dec 2021 16:44:22 +0100
changeset 48561 04688c51f81f
parent 48560 d6c53b40b078
child 48562 bf5dc156bb4c
exchangev2: remove it As discussed on the mailing list, this is incomplete and unused with little hope of revival. Differential Revision: https://phab.mercurial-scm.org/D11954
mercurial/configitems.py
mercurial/debugcommands.py
mercurial/exchange.py
mercurial/exchangev2.py
mercurial/helptext/internals/wireprotocol.txt
mercurial/hgweb/hgweb_mod.py
mercurial/httppeer.py
mercurial/sshpeer.py
mercurial/wireprotoserver.py
mercurial/wireprototypes.py
mercurial/wireprotov1server.py
mercurial/wireprotov2peer.py
mercurial/wireprotov2server.py
tests/test-bookmarks-pushpull.t
tests/test-bundle2-exchange.t
tests/test-bundle2-pushback.t
tests/test-bundle2-remote-changegroup.t
tests/test-check-interfaces.py
tests/test-clone.t
tests/test-http-api-httpv2.t
tests/test-http-api.t
tests/test-http-protocol.t
tests/test-largefiles-wireproto.t
tests/test-pull-network.t
tests/test-ssh-bundle1.t
tests/test-ssh-clone-r.t
tests/test-ssh-proto-unbundle.t
tests/test-ssh-proto.t
tests/test-ssh.t
tests/test-wireproto-caching.t
tests/test-wireproto-command-branchmap.t
tests/test-wireproto-command-capabilities.t
tests/test-wireproto-command-changesetdata.t
tests/test-wireproto-command-filedata.t
tests/test-wireproto-command-filesdata.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-manifestdata.t
tests/test-wireproto-command-pushkey.t
tests/test-wireproto-command-rawstorefiledata.t
tests/test-wireproto-content-redirects.t
tests/test-wireproto-exchangev2-shallow.t
tests/test-wireproto-exchangev2.t
tests/wireprotohelpers.sh
tests/wireprotosimplecache.py
--- a/mercurial/configitems.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/configitems.py	Tue Dec 07 16:44:22 2021 +0100
@@ -1102,16 +1102,6 @@
 )
 coreconfigitem(
     b'experimental',
-    b'httppeer.advertise-v2',
-    default=False,
-)
-coreconfigitem(
-    b'experimental',
-    b'httppeer.v2-encoder-order',
-    default=None,
-)
-coreconfigitem(
-    b'experimental',
     b'httppostargs',
     default=False,
 )
@@ -1211,11 +1201,6 @@
 )
 coreconfigitem(
     b'experimental',
-    b'sshserver.support-v2',
-    default=False,
-)
-coreconfigitem(
-    b'experimental',
     b'sparse-read',
     default=False,
 )
@@ -1241,26 +1226,6 @@
 )
 coreconfigitem(
     b'experimental',
-    b'sshpeer.advertise-v2',
-    default=False,
-)
-coreconfigitem(
-    b'experimental',
-    b'web.apiserver',
-    default=False,
-)
-coreconfigitem(
-    b'experimental',
-    b'web.api.http-v2',
-    default=False,
-)
-coreconfigitem(
-    b'experimental',
-    b'web.api.debugreflect',
-    default=False,
-)
-coreconfigitem(
-    b'experimental',
     b'web.full-garbage-collection-rate',
     default=1,  # still forcing a full collection on each request
 )
--- a/mercurial/debugcommands.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/debugcommands.py	Tue Dec 07 16:44:22 2021 +0100
@@ -91,7 +91,6 @@
     vfs as vfsmod,
     wireprotoframing,
     wireprotoserver,
-    wireprotov2peer,
 )
 from .interfaces import repository
 from .utils import (
@@ -4352,8 +4351,8 @@
 
     ``--peer`` can be used to bypass the handshake protocol and construct a
     peer instance using the specified class type. Valid values are ``raw``,
-    ``http2``, ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending
-    raw data payloads and don't support higher-level command actions.
+    ``ssh1``. ``raw`` instances only allow sending raw data payloads and
+    don't support higher-level command actions.
 
     ``--noreadstderr`` can be used to disable automatic reading from stderr
     of the peer (for SSH connections only). Disabling automatic reading of
@@ -4528,13 +4527,11 @@
 
     if opts[b'peer'] and opts[b'peer'] not in (
         b'raw',
-        b'http2',
         b'ssh1',
-        b'ssh2',
     ):
         raise error.Abort(
             _(b'invalid value for --peer'),
-            hint=_(b'valid values are "raw", "ssh1", and "ssh2"'),
+            hint=_(b'valid values are "raw" and "ssh1"'),
         )
 
     if path and opts[b'localssh']:
@@ -4602,18 +4599,6 @@
                 None,
                 autoreadstderr=autoreadstderr,
             )
-        elif opts[b'peer'] == b'ssh2':
-            ui.write(_(b'creating ssh peer for wire protocol version 2\n'))
-            peer = sshpeer.sshv2peer(
-                ui,
-                url,
-                proc,
-                stdin,
-                stdout,
-                stderr,
-                None,
-                autoreadstderr=autoreadstderr,
-            )
         elif opts[b'peer'] == b'raw':
             ui.write(_(b'using raw connection to peer\n'))
             peer = None
@@ -4666,34 +4651,7 @@
 
         opener = urlmod.opener(ui, authinfo, **openerargs)
 
-        if opts[b'peer'] == b'http2':
-            ui.write(_(b'creating http peer for wire protocol version 2\n'))
-            # We go through makepeer() because we need an API descriptor for
-            # the peer instance to be useful.
-            maybe_silent = (
-                ui.silent()
-                if opts[b'nologhandshake']
-                else util.nullcontextmanager()
-            )
-            with maybe_silent, ui.configoverride(
-                {(b'experimental', b'httppeer.advertise-v2'): True}
-            ):
-                peer = httppeer.makepeer(ui, path, opener=opener)
-
-            if not isinstance(peer, httppeer.httpv2peer):
-                raise error.Abort(
-                    _(
-                        b'could not instantiate HTTP peer for '
-                        b'wire protocol version 2'
-                    ),
-                    hint=_(
-                        b'the server may not have the feature '
-                        b'enabled or is not allowing this '
-                        b'client version'
-                    ),
-                )
-
-        elif opts[b'peer'] == b'raw':
+        if opts[b'peer'] == b'raw':
             ui.write(_(b'using raw connection to peer\n'))
             peer = None
         elif opts[b'peer']:
@@ -4774,17 +4732,10 @@
                 with peer.commandexecutor() as e:
                     res = e.callcommand(command, args).result()
 
-                if isinstance(res, wireprotov2peer.commandresponse):
-                    val = res.objects()
-                    ui.status(
-                        _(b'response: %s\n')
-                        % stringutil.pprint(val, bprefix=True, indent=2)
-                    )
-                else:
-                    ui.status(
-                        _(b'response: %s\n')
-                        % stringutil.pprint(res, bprefix=True, indent=2)
-                    )
+                ui.status(
+                    _(b'response: %s\n')
+                    % stringutil.pprint(res, bprefix=True, indent=2)
+                )
 
         elif action == b'batchbegin':
             if batchedcommands is not None:
--- a/mercurial/exchange.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/exchange.py	Tue Dec 07 16:44:22 2021 +0100
@@ -22,7 +22,6 @@
     changegroup,
     discovery,
     error,
-    exchangev2,
     lock as lockmod,
     logexchange,
     narrowspec,
@@ -1666,21 +1665,17 @@
         ):
             add_confirm_callback(repo, pullop)
 
-        # Use the modern wire protocol, if available.
-        if remote.capable(b'command-changesetdata'):
-            exchangev2.pull(pullop)
-        else:
-            # This should ideally be in _pullbundle2(). However, it needs to run
-            # before discovery to avoid extra work.
-            _maybeapplyclonebundle(pullop)
-            streamclone.maybeperformlegacystreamclone(pullop)
-            _pulldiscovery(pullop)
-            if pullop.canusebundle2:
-                _fullpullbundle2(repo, pullop)
-            _pullchangeset(pullop)
-            _pullphase(pullop)
-            _pullbookmarks(pullop)
-            _pullobsolete(pullop)
+        # This should ideally be in _pullbundle2(). However, it needs to run
+        # before discovery to avoid extra work.
+        _maybeapplyclonebundle(pullop)
+        streamclone.maybeperformlegacystreamclone(pullop)
+        _pulldiscovery(pullop)
+        if pullop.canusebundle2:
+            _fullpullbundle2(repo, pullop)
+        _pullchangeset(pullop)
+        _pullphase(pullop)
+        _pullbookmarks(pullop)
+        _pullobsolete(pullop)
 
     # storing remotenames
     if repo.ui.configbool(b'experimental', b'remotenames'):
--- a/mercurial/exchangev2.py	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,804 +0,0 @@
-# exchangev2.py - repository exchange for wire protocol version 2
-#
-# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from __future__ import absolute_import
-
-import collections
-import weakref
-
-from .i18n import _
-from .node import short
-from . import (
-    bookmarks,
-    error,
-    mdiff,
-    narrowspec,
-    phases,
-    pycompat,
-    requirements as requirementsmod,
-    setdiscovery,
-)
-from .interfaces import repository
-
-
-def pull(pullop):
-    """Pull using wire protocol version 2."""
-    repo = pullop.repo
-    remote = pullop.remote
-
-    usingrawchangelogandmanifest = _checkuserawstorefiledata(pullop)
-
-    # If this is a clone and it was requested to perform a "stream clone",
-    # we obtain the raw files data from the remote then fall back to an
-    # incremental pull. This is somewhat hacky and is not nearly robust enough
-    # for long-term usage.
-    if usingrawchangelogandmanifest:
-        with repo.transaction(b'clone'):
-            _fetchrawstorefiles(repo, remote)
-            repo.invalidate(clearfilecache=True)
-
-    tr = pullop.trmanager.transaction()
-
-    # We don't use the repo's narrow matcher here because the patterns passed
-    # to exchange.pull() could be different.
-    narrowmatcher = narrowspec.match(
-        repo.root,
-        # Empty maps to nevermatcher. So always
-        # set includes if missing.
-        pullop.includepats or {b'path:.'},
-        pullop.excludepats,
-    )
-
-    if pullop.includepats or pullop.excludepats:
-        pathfilter = {}
-        if pullop.includepats:
-            pathfilter[b'include'] = sorted(pullop.includepats)
-        if pullop.excludepats:
-            pathfilter[b'exclude'] = sorted(pullop.excludepats)
-    else:
-        pathfilter = None
-
-    # Figure out what needs to be fetched.
-    common, fetch, remoteheads = _pullchangesetdiscovery(
-        repo, remote, pullop.heads, abortwhenunrelated=pullop.force
-    )
-
-    # And fetch the data.
-    pullheads = pullop.heads or remoteheads
-    csetres = _fetchchangesets(repo, tr, remote, common, fetch, pullheads)
-
-    # New revisions are written to the changelog. But all other updates
-    # are deferred. Do those now.
-
-    # Ensure all new changesets are draft by default. If the repo is
-    # publishing, the phase will be adjusted by the loop below.
-    if csetres[b'added']:
-        phases.registernew(
-            repo, tr, phases.draft, [repo[n].rev() for n in csetres[b'added']]
-        )
-
-    # And adjust the phase of all changesets accordingly.
-    for phasenumber, phase in phases.phasenames.items():
-        if phase == b'secret' or not csetres[b'nodesbyphase'][phase]:
-            continue
-
-        phases.advanceboundary(
-            repo,
-            tr,
-            phasenumber,
-            csetres[b'nodesbyphase'][phase],
-        )
-
-    # Write bookmark updates.
-    bookmarks.updatefromremote(
-        repo.ui,
-        repo,
-        csetres[b'bookmarks'],
-        remote.url(),
-        pullop.gettransaction,
-        explicit=pullop.explicitbookmarks,
-    )
-
-    manres = _fetchmanifests(repo, tr, remote, csetres[b'manifestnodes'])
-
-    # We don't properly support shallow changeset and manifest yet. So we apply
-    # depth limiting locally.
-    if pullop.depth:
-        relevantcsetnodes = set()
-        clnode = repo.changelog.node
-
-        for rev in repo.revs(
-            b'ancestors(%ln, %s)', pullheads, pullop.depth - 1
-        ):
-            relevantcsetnodes.add(clnode(rev))
-
-        csetrelevantfilter = lambda n: n in relevantcsetnodes
-
-    else:
-        csetrelevantfilter = lambda n: True
-
-    # If obtaining the raw store files, we need to scan the full repo to
-    # derive all the changesets, manifests, and linkrevs.
-    if usingrawchangelogandmanifest:
-        csetsforfiles = []
-        mnodesforfiles = []
-        manifestlinkrevs = {}
-
-        for rev in repo:
-            ctx = repo[rev]
-            node = ctx.node()
-
-            if not csetrelevantfilter(node):
-                continue
-
-            mnode = ctx.manifestnode()
-
-            csetsforfiles.append(node)
-            mnodesforfiles.append(mnode)
-            manifestlinkrevs[mnode] = rev
-
-    else:
-        csetsforfiles = [n for n in csetres[b'added'] if csetrelevantfilter(n)]
-        mnodesforfiles = manres[b'added']
-        manifestlinkrevs = manres[b'linkrevs']
-
-    # Find all file nodes referenced by added manifests and fetch those
-    # revisions.
-    fnodes = _derivefilesfrommanifests(repo, narrowmatcher, mnodesforfiles)
-    _fetchfilesfromcsets(
-        repo,
-        tr,
-        remote,
-        pathfilter,
-        fnodes,
-        csetsforfiles,
-        manifestlinkrevs,
-        shallow=bool(pullop.depth),
-    )
-
-
-def _checkuserawstorefiledata(pullop):
-    """Check whether we should use rawstorefiledata command to retrieve data."""
-
-    repo = pullop.repo
-    remote = pullop.remote
-
-    # Command to obtain raw store data isn't available.
-    if b'rawstorefiledata' not in remote.apidescriptor[b'commands']:
-        return False
-
-    # Only honor if user requested stream clone operation.
-    if not pullop.streamclonerequested:
-        return False
-
-    # Only works on empty repos.
-    if len(repo):
-        return False
-
-    # TODO This is super hacky. There needs to be a storage API for this. We
-    # also need to check for compatibility with the remote.
-    if requirementsmod.REVLOGV1_REQUIREMENT not in repo.requirements:
-        return False
-
-    return True
-
-
-def _fetchrawstorefiles(repo, remote):
-    with remote.commandexecutor() as e:
-        objs = e.callcommand(
-            b'rawstorefiledata',
-            {
-                b'files': [b'changelog', b'manifestlog'],
-            },
-        ).result()
-
-        # First object is a summary of files data that follows.
-        overall = next(objs)
-
-        progress = repo.ui.makeprogress(
-            _(b'clone'), total=overall[b'totalsize'], unit=_(b'bytes')
-        )
-        with progress:
-            progress.update(0)
-
-            # Next are pairs of file metadata, data.
-            while True:
-                try:
-                    filemeta = next(objs)
-                except StopIteration:
-                    break
-
-                for k in (b'location', b'path', b'size'):
-                    if k not in filemeta:
-                        raise error.Abort(
-                            _(b'remote file data missing key: %s') % k
-                        )
-
-                if filemeta[b'location'] == b'store':
-                    vfs = repo.svfs
-                else:
-                    raise error.Abort(
-                        _(b'invalid location for raw file data: %s')
-                        % filemeta[b'location']
-                    )
-
-                bytesremaining = filemeta[b'size']
-
-                with vfs.open(filemeta[b'path'], b'wb') as fh:
-                    while True:
-                        try:
-                            chunk = next(objs)
-                        except StopIteration:
-                            break
-
-                        bytesremaining -= len(chunk)
-
-                        if bytesremaining < 0:
-                            raise error.Abort(
-                                _(
-                                    b'received invalid number of bytes for file '
-                                    b'data; expected %d, got extra'
-                                )
-                                % filemeta[b'size']
-                            )
-
-                        progress.increment(step=len(chunk))
-                        fh.write(chunk)
-
-                        try:
-                            if chunk.islast:
-                                break
-                        except AttributeError:
-                            raise error.Abort(
-                                _(
-                                    b'did not receive indefinite length bytestring '
-                                    b'for file data'
-                                )
-                            )
-
-                if bytesremaining:
-                    raise error.Abort(
-                        _(
-                            b'received invalid number of bytes for'
-                            b'file data; expected %d got %d'
-                        )
-                        % (
-                            filemeta[b'size'],
-                            filemeta[b'size'] - bytesremaining,
-                        )
-                    )
-
-
-def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True):
-    """Determine which changesets need to be pulled."""
-
-    if heads:
-        knownnode = repo.changelog.hasnode
-        if all(knownnode(head) for head in heads):
-            return heads, False, heads
-
-    # TODO wire protocol version 2 is capable of more efficient discovery
-    # than setdiscovery. Consider implementing something better.
-    common, fetch, remoteheads = setdiscovery.findcommonheads(
-        repo.ui, repo, remote, abortwhenunrelated=abortwhenunrelated
-    )
-
-    common = set(common)
-    remoteheads = set(remoteheads)
-
-    # If a remote head is filtered locally, put it back in the common set.
-    # See the comment in exchange._pulldiscoverychangegroup() for more.
-
-    if fetch and remoteheads:
-        has_node = repo.unfiltered().changelog.index.has_node
-
-        common |= {head for head in remoteheads if has_node(head)}
-
-        if set(remoteheads).issubset(common):
-            fetch = []
-
-    common.discard(repo.nullid)
-
-    return common, fetch, remoteheads
-
-
-def _fetchchangesets(repo, tr, remote, common, fetch, remoteheads):
-    # TODO consider adding a step here where we obtain the DAG shape first
-    # (or ask the server to slice changesets into chunks for us) so that
-    # we can perform multiple fetches in batches. This will facilitate
-    # resuming interrupted clones, higher server-side cache hit rates due
-    # to smaller segments, etc.
-    with remote.commandexecutor() as e:
-        objs = e.callcommand(
-            b'changesetdata',
-            {
-                b'revisions': [
-                    {
-                        b'type': b'changesetdagrange',
-                        b'roots': sorted(common),
-                        b'heads': sorted(remoteheads),
-                    }
-                ],
-                b'fields': {b'bookmarks', b'parents', b'phase', b'revision'},
-            },
-        ).result()
-
-        # The context manager waits on all response data when exiting. So
-        # we need to remain in the context manager in order to stream data.
-        return _processchangesetdata(repo, tr, objs)
-
-
-def _processchangesetdata(repo, tr, objs):
-    repo.hook(b'prechangegroup', throw=True, **pycompat.strkwargs(tr.hookargs))
-
-    urepo = repo.unfiltered()
-    cl = urepo.changelog
-
-    cl.delayupdate(tr)
-
-    # The first emitted object is a header describing the data that
-    # follows.
-    meta = next(objs)
-
-    progress = repo.ui.makeprogress(
-        _(b'changesets'), unit=_(b'chunks'), total=meta.get(b'totalitems')
-    )
-
-    manifestnodes = {}
-    added = []
-
-    def linkrev(node):
-        repo.ui.debug(b'add changeset %s\n' % short(node))
-        # Linkrev for changelog is always self.
-        return len(cl)
-
-    def ondupchangeset(cl, rev):
-        added.append(cl.node(rev))
-
-    def onchangeset(cl, rev):
-        progress.increment()
-
-        revision = cl.changelogrevision(rev)
-        added.append(cl.node(rev))
-
-        # We need to preserve the mapping of changelog revision to node
-        # so we can set the linkrev accordingly when manifests are added.
-        manifestnodes[rev] = revision.manifest
-
-        repo.register_changeset(rev, revision)
-
-    nodesbyphase = {phase: set() for phase in phases.phasenames.values()}
-    remotebookmarks = {}
-
-    # addgroup() expects a 7-tuple describing revisions. This normalizes
-    # the wire data to that format.
-    #
-    # This loop also aggregates non-revision metadata, such as phase
-    # data.
-    def iterrevisions():
-        for cset in objs:
-            node = cset[b'node']
-
-            if b'phase' in cset:
-                nodesbyphase[cset[b'phase']].add(node)
-
-            for mark in cset.get(b'bookmarks', []):
-                remotebookmarks[mark] = node
-
-            # TODO add mechanism for extensions to examine records so they
-            # can siphon off custom data fields.
-
-            extrafields = {}
-
-            for field, size in cset.get(b'fieldsfollowing', []):
-                extrafields[field] = next(objs)
-
-            # Some entries might only be metadata only updates.
-            if b'revision' not in extrafields:
-                continue
-
-            data = extrafields[b'revision']
-
-            yield (
-                node,
-                cset[b'parents'][0],
-                cset[b'parents'][1],
-                # Linknode is always itself for changesets.
-                cset[b'node'],
-                # We always send full revisions. So delta base is not set.
-                repo.nullid,
-                mdiff.trivialdiffheader(len(data)) + data,
-                # Flags not yet supported.
-                0,
-                # Sidedata not yet supported
-                {},
-            )
-
-    cl.addgroup(
-        iterrevisions(),
-        linkrev,
-        weakref.proxy(tr),
-        alwayscache=True,
-        addrevisioncb=onchangeset,
-        duplicaterevisioncb=ondupchangeset,
-    )
-
-    progress.complete()
-
-    return {
-        b'added': added,
-        b'nodesbyphase': nodesbyphase,
-        b'bookmarks': remotebookmarks,
-        b'manifestnodes': manifestnodes,
-    }
-
-
-def _fetchmanifests(repo, tr, remote, manifestnodes):
-    rootmanifest = repo.manifestlog.getstorage(b'')
-
-    # Some manifests can be shared between changesets. Filter out revisions
-    # we already know about.
-    fetchnodes = []
-    linkrevs = {}
-    seen = set()
-
-    for clrev, node in sorted(pycompat.iteritems(manifestnodes)):
-        if node in seen:
-            continue
-
-        try:
-            rootmanifest.rev(node)
-        except error.LookupError:
-            fetchnodes.append(node)
-            linkrevs[node] = clrev
-
-        seen.add(node)
-
-    # TODO handle tree manifests
-
-    # addgroup() expects 7-tuple describing revisions. This normalizes
-    # the wire data to that format.
-    def iterrevisions(objs, progress):
-        for manifest in objs:
-            node = manifest[b'node']
-
-            extrafields = {}
-
-            for field, size in manifest.get(b'fieldsfollowing', []):
-                extrafields[field] = next(objs)
-
-            if b'delta' in extrafields:
-                basenode = manifest[b'deltabasenode']
-                delta = extrafields[b'delta']
-            elif b'revision' in extrafields:
-                basenode = repo.nullid
-                revision = extrafields[b'revision']
-                delta = mdiff.trivialdiffheader(len(revision)) + revision
-            else:
-                continue
-
-            yield (
-                node,
-                manifest[b'parents'][0],
-                manifest[b'parents'][1],
-                # The value passed in is passed to the lookup function passed
-                # to addgroup(). We already have a map of manifest node to
-                # changelog revision number. So we just pass in the
-                # manifest node here and use linkrevs.__getitem__ as the
-                # resolution function.
-                node,
-                basenode,
-                delta,
-                # Flags not yet supported.
-                0,
-                # Sidedata not yet supported.
-                {},
-            )
-
-            progress.increment()
-
-    progress = repo.ui.makeprogress(
-        _(b'manifests'), unit=_(b'chunks'), total=len(fetchnodes)
-    )
-
-    commandmeta = remote.apidescriptor[b'commands'][b'manifestdata']
-    batchsize = commandmeta.get(b'recommendedbatchsize', 10000)
-    # TODO make size configurable on client?
-
-    # We send commands 1 at a time to the remote. This is not the most
-    # efficient because we incur a round trip at the end of each batch.
-    # However, the existing frame-based reactor keeps consuming server
-    # data in the background. And this results in response data buffering
-    # in memory. This can consume gigabytes of memory.
-    # TODO send multiple commands in a request once background buffering
-    # issues are resolved.
-
-    added = []
-
-    for i in pycompat.xrange(0, len(fetchnodes), batchsize):
-        batch = [node for node in fetchnodes[i : i + batchsize]]
-        if not batch:
-            continue
-
-        with remote.commandexecutor() as e:
-            objs = e.callcommand(
-                b'manifestdata',
-                {
-                    b'tree': b'',
-                    b'nodes': batch,
-                    b'fields': {b'parents', b'revision'},
-                    b'haveparents': True,
-                },
-            ).result()
-
-            # Chomp off header object.
-            next(objs)
-
-            def onchangeset(cl, rev):
-                added.append(cl.node(rev))
-
-            rootmanifest.addgroup(
-                iterrevisions(objs, progress),
-                linkrevs.__getitem__,
-                weakref.proxy(tr),
-                addrevisioncb=onchangeset,
-                duplicaterevisioncb=onchangeset,
-            )
-
-    progress.complete()
-
-    return {
-        b'added': added,
-        b'linkrevs': linkrevs,
-    }
-
-
-def _derivefilesfrommanifests(repo, matcher, manifestnodes):
-    """Determine what file nodes are relevant given a set of manifest nodes.
-
-    Returns a dict mapping file paths to dicts of file node to first manifest
-    node.
-    """
-    ml = repo.manifestlog
-    fnodes = collections.defaultdict(dict)
-
-    progress = repo.ui.makeprogress(
-        _(b'scanning manifests'), total=len(manifestnodes)
-    )
-
-    with progress:
-        for manifestnode in manifestnodes:
-            m = ml.get(b'', manifestnode)
-
-            # TODO this will pull in unwanted nodes because it takes the storage
-            # delta into consideration. What we really want is something that
-            # takes the delta between the manifest's parents. And ideally we
-            # would ignore file nodes that are known locally. For now, ignore
-            # both these limitations. This will result in incremental fetches
-            # requesting data we already have. So this is far from ideal.
-            md = m.readfast()
-
-            for path, fnode in md.items():
-                if matcher(path):
-                    fnodes[path].setdefault(fnode, manifestnode)
-
-            progress.increment()
-
-    return fnodes
-
-
-def _fetchfiles(repo, tr, remote, fnodes, linkrevs):
-    """Fetch file data from explicit file revisions."""
-
-    def iterrevisions(objs, progress):
-        for filerevision in objs:
-            node = filerevision[b'node']
-
-            extrafields = {}
-
-            for field, size in filerevision.get(b'fieldsfollowing', []):
-                extrafields[field] = next(objs)
-
-            if b'delta' in extrafields:
-                basenode = filerevision[b'deltabasenode']
-                delta = extrafields[b'delta']
-            elif b'revision' in extrafields:
-                basenode = repo.nullid
-                revision = extrafields[b'revision']
-                delta = mdiff.trivialdiffheader(len(revision)) + revision
-            else:
-                continue
-
-            yield (
-                node,
-                filerevision[b'parents'][0],
-                filerevision[b'parents'][1],
-                node,
-                basenode,
-                delta,
-                # Flags not yet supported.
-                0,
-                # Sidedata not yet supported.
-                {},
-            )
-
-            progress.increment()
-
-    progress = repo.ui.makeprogress(
-        _(b'files'),
-        unit=_(b'chunks'),
-        total=sum(len(v) for v in pycompat.itervalues(fnodes)),
-    )
-
-    # TODO make batch size configurable
-    batchsize = 10000
-    fnodeslist = [x for x in sorted(fnodes.items())]
-
-    for i in pycompat.xrange(0, len(fnodeslist), batchsize):
-        batch = [x for x in fnodeslist[i : i + batchsize]]
-        if not batch:
-            continue
-
-        with remote.commandexecutor() as e:
-            fs = []
-            locallinkrevs = {}
-
-            for path, nodes in batch:
-                fs.append(
-                    (
-                        path,
-                        e.callcommand(
-                            b'filedata',
-                            {
-                                b'path': path,
-                                b'nodes': sorted(nodes),
-                                b'fields': {b'parents', b'revision'},
-                                b'haveparents': True,
-                            },
-                        ),
-                    )
-                )
-
-                locallinkrevs[path] = {
-                    node: linkrevs[manifestnode]
-                    for node, manifestnode in pycompat.iteritems(nodes)
-                }
-
-            for path, f in fs:
-                objs = f.result()
-
-                # Chomp off header objects.
-                next(objs)
-
-                store = repo.file(path)
-                store.addgroup(
-                    iterrevisions(objs, progress),
-                    locallinkrevs[path].__getitem__,
-                    weakref.proxy(tr),
-                )
-
-
-def _fetchfilesfromcsets(
-    repo, tr, remote, pathfilter, fnodes, csets, manlinkrevs, shallow=False
-):
-    """Fetch file data from explicit changeset revisions."""
-
-    def iterrevisions(objs, remaining, progress):
-        while remaining:
-            filerevision = next(objs)
-
-            node = filerevision[b'node']
-
-            extrafields = {}
-
-            for field, size in filerevision.get(b'fieldsfollowing', []):
-                extrafields[field] = next(objs)
-
-            if b'delta' in extrafields:
-                basenode = filerevision[b'deltabasenode']
-                delta = extrafields[b'delta']
-            elif b'revision' in extrafields:
-                basenode = repo.nullid
-                revision = extrafields[b'revision']
-                delta = mdiff.trivialdiffheader(len(revision)) + revision
-            else:
-                continue
-
-            if b'linknode' in filerevision:
-                linknode = filerevision[b'linknode']
-            else:
-                linknode = node
-
-            yield (
-                node,
-                filerevision[b'parents'][0],
-                filerevision[b'parents'][1],
-                linknode,
-                basenode,
-                delta,
-                # Flags not yet supported.
-                0,
-                # Sidedata not yet supported.
-                {},
-            )
-
-            progress.increment()
-            remaining -= 1
-
-    progress = repo.ui.makeprogress(
-        _(b'files'),
-        unit=_(b'chunks'),
-        total=sum(len(v) for v in pycompat.itervalues(fnodes)),
-    )
-
-    commandmeta = remote.apidescriptor[b'commands'][b'filesdata']
-    batchsize = commandmeta.get(b'recommendedbatchsize', 50000)
-
-    shallowfiles = repository.REPO_FEATURE_SHALLOW_FILE_STORAGE in repo.features
-    fields = {b'parents', b'revision'}
-    clrev = repo.changelog.rev
-
-    # There are no guarantees that we'll have ancestor revisions if
-    # a) this repo has shallow file storage b) shallow data fetching is enabled.
-    # Force remote to not delta against possibly unknown revisions when these
-    # conditions hold.
-    haveparents = not (shallowfiles or shallow)
-
-    # Similarly, we may not have calculated linkrevs for all incoming file
-    # revisions. Ask the remote to do work for us in this case.
-    if not haveparents:
-        fields.add(b'linknode')
-
-    for i in pycompat.xrange(0, len(csets), batchsize):
-        batch = [x for x in csets[i : i + batchsize]]
-        if not batch:
-            continue
-
-        with remote.commandexecutor() as e:
-            args = {
-                b'revisions': [
-                    {
-                        b'type': b'changesetexplicit',
-                        b'nodes': batch,
-                    }
-                ],
-                b'fields': fields,
-                b'haveparents': haveparents,
-            }
-
-            if pathfilter:
-                args[b'pathfilter'] = pathfilter
-
-            objs = e.callcommand(b'filesdata', args).result()
-
-            # First object is an overall header.
-            overall = next(objs)
-
-            # We have overall['totalpaths'] segments.
-            for i in pycompat.xrange(overall[b'totalpaths']):
-                header = next(objs)
-
-                path = header[b'path']
-                store = repo.file(path)
-
-                linkrevs = {
-                    fnode: manlinkrevs[mnode]
-                    for fnode, mnode in pycompat.iteritems(fnodes[path])
-                }
-
-                def getlinkrev(node):
-                    if node in linkrevs:
-                        return linkrevs[node]
-                    else:
-                        return clrev(node)
-
-                store.addgroup(
-                    iterrevisions(objs, header[b'totalitems'], progress),
-                    getlinkrev,
-                    weakref.proxy(tr),
-                    maybemissingparents=shallow,
-                )
--- a/mercurial/helptext/internals/wireprotocol.txt	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/helptext/internals/wireprotocol.txt	Tue Dec 07 16:44:22 2021 +0100
@@ -332,95 +332,6 @@
 after responses. In other words, the length of the response contains the
 trailing ``\n``.
 
-Clients supporting version 2 of the SSH transport send a line beginning
-with ``upgrade`` before the ``hello`` and ``between`` commands. The line
-(which isn't a well-formed command line because it doesn't consist of a
-single command name) serves to both communicate the client's intent to
-switch to transport version 2 (transports are version 1 by default) as
-well as to advertise the client's transport-level capabilities so the
-server may satisfy that request immediately.
-
-The upgrade line has the form:
-
-    upgrade <token> <transport capabilities>
-
-That is the literal string ``upgrade`` followed by a space, followed by
-a randomly generated string, followed by a space, followed by a string
-denoting the client's transport capabilities.
-
-The token can be anything. However, a random UUID is recommended. (Use
-of version 4 UUIDs is recommended because version 1 UUIDs can leak the
-client's MAC address.)
-
-The transport capabilities string is a URL/percent encoded string
-containing key-value pairs defining the client's transport-level
-capabilities. The following capabilities are defined:
-
-proto
-   A comma-delimited list of transport protocol versions the client
-   supports. e.g. ``ssh-v2``.
-
-If the server does not recognize the ``upgrade`` line, it should issue
-an empty response and continue processing the ``hello`` and ``between``
-commands. Here is an example handshake between a version 2 aware client
-and a non version 2 aware server:
-
-   c: upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2
-   c: hello\n
-   c: between\n
-   c: pairs 81\n
-   c: 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-   s: 0\n
-   s: 324\n
-   s: capabilities: lookup changegroupsubset branchmap pushkey known getbundle ...\n
-   s: 1\n
-   s: \n
-
-(The initial ``0\n`` line from the server indicates an empty response to
-the unknown ``upgrade ..`` command/line.)
-
-If the server recognizes the ``upgrade`` line and is willing to satisfy that
-upgrade request, it replies to with a payload of the following form:
-
-   upgraded <token> <transport name>\n
-
-This line is the literal string ``upgraded``, a space, the token that was
-specified by the client in its ``upgrade ...`` request line, a space, and the
-name of the transport protocol that was chosen by the server. The transport
-name MUST match one of the names the client specified in the ``proto`` field
-of its ``upgrade ...`` request line.
-
-If a server issues an ``upgraded`` response, it MUST also read and ignore
-the lines associated with the ``hello`` and ``between`` command requests
-that were issued by the server. It is assumed that the negotiated transport
-will respond with equivalent requested information following the transport
-handshake.
-
-All data following the ``\n`` terminating the ``upgraded`` line is the
-domain of the negotiated transport. It is common for the data immediately
-following to contain additional metadata about the state of the transport and
-the server. However, this isn't strictly speaking part of the transport
-handshake and isn't covered by this section.
-
-Here is an example handshake between a version 2 aware client and a version
-2 aware server:
-
-   c:  upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=ssh-v2
-   c:  hello\n
-   c:  between\n
-   c:  pairs 81\n
-   c:  0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-   s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n
-   s: <additional transport specific data>
-
-The client-issued token that is echoed in the response provides a more
-resilient mechanism for differentiating *banner* output from Mercurial
-output. In version 1, properly formatted banner output could get confused
-for Mercurial server output. By submitting a randomly generated token
-that is then present in the response, the client can look for that token
-in response lines and have reasonable certainty that the line did not
-originate from a *banner* message.
-
 SSH Version 1 Transport
 -----------------------
 
@@ -488,31 +399,6 @@
 should issue a ``protocaps`` command after the initial handshake to annonunce
 its own capabilities. The client capabilities are persistent.
 
-SSH Version 2 Transport
------------------------
-
-**Experimental and under development**
-
-Version 2 of the SSH transport behaves identically to version 1 of the SSH
-transport with the exception of handshake semantics. See above for how
-version 2 of the SSH transport is negotiated.
-
-Immediately following the ``upgraded`` line signaling a switch to version
-2 of the SSH protocol, the server automatically sends additional details
-about the capabilities of the remote server. This has the form:
-
-   <integer length of value>\n
-   capabilities: ...\n
-
-e.g.
-
-   s: upgraded 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a ssh-v2\n
-   s: 240\n
-   s: capabilities: known getbundle batch ...\n
-
-Following capabilities advertisement, the peers communicate using version
-1 of the SSH transport.
-
 Capabilities
 ============
 
--- a/mercurial/hgweb/hgweb_mod.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/hgweb/hgweb_mod.py	Tue Dec 07 16:44:22 2021 +0100
@@ -366,17 +366,6 @@
             # replace it.
             res.headers[b'Content-Security-Policy'] = rctx.csp
 
-        # /api/* is reserved for various API implementations. Dispatch
-        # accordingly. But URL paths can conflict with subrepos and virtual
-        # repos in hgwebdir. So until we have a workaround for this, only
-        # expose the URLs if the feature is enabled.
-        apienabled = rctx.repo.ui.configbool(b'experimental', b'web.apiserver')
-        if apienabled and req.dispatchparts and req.dispatchparts[0] == b'api':
-            wireprotoserver.handlewsgiapirequest(
-                rctx, req, res, self.check_perm
-            )
-            return res.sendresponse()
-
         handled = wireprotoserver.handlewsgirequest(
             rctx, req, res, self.check_perm
         )
--- a/mercurial/httppeer.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/httppeer.py	Tue Dec 07 16:44:22 2021 +0100
@@ -13,7 +13,6 @@
 import os
 import socket
 import struct
-import weakref
 
 from .i18n import _
 from .pycompat import getattr
@@ -25,21 +24,9 @@
     statichttprepo,
     url as urlmod,
     util,
-    wireprotoframing,
-    wireprototypes,
     wireprotov1peer,
-    wireprotov2peer,
-    wireprotov2server,
 )
-from .interfaces import (
-    repository,
-    util as interfaceutil,
-)
-from .utils import (
-    cborutil,
-    stringutil,
-    urlutil,
-)
+from .utils import urlutil
 
 httplib = util.httplib
 urlerr = util.urlerr
@@ -331,9 +318,7 @@
         self.respurl = respurl
 
 
-def parsev1commandresponse(
-    ui, baseurl, requrl, qs, resp, compressible, allowcbor=False
-):
+def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible):
     # record the url we got redirected to
     redirected = False
     respurl = pycompat.bytesurl(resp.geturl())
@@ -376,17 +361,6 @@
     try:
         subtype = proto.split(b'-', 1)[1]
 
-        # Unless we end up supporting CBOR in the legacy wire protocol,
-        # this should ONLY be encountered for the initial capabilities
-        # request during handshake.
-        if subtype == b'cbor':
-            if allowcbor:
-                return respurl, proto, resp
-            else:
-                raise error.RepoError(
-                    _(b'unexpected CBOR response from server')
-                )
-
         version_info = tuple([int(n) for n in subtype.split(b'.')])
     except ValueError:
         raise error.RepoError(
@@ -564,85 +538,6 @@
         raise exception
 
 
-def sendv2request(
-    ui, opener, requestbuilder, apiurl, permission, requests, redirect
-):
-    wireprotoframing.populatestreamencoders()
-
-    uiencoders = ui.configlist(b'experimental', b'httppeer.v2-encoder-order')
-
-    if uiencoders:
-        encoders = []
-
-        for encoder in uiencoders:
-            if encoder not in wireprotoframing.STREAM_ENCODERS:
-                ui.warn(
-                    _(
-                        b'wire protocol version 2 encoder referenced in '
-                        b'config (%s) is not known; ignoring\n'
-                    )
-                    % encoder
-                )
-            else:
-                encoders.append(encoder)
-
-    else:
-        encoders = wireprotoframing.STREAM_ENCODERS_ORDER
-
-    reactor = wireprotoframing.clientreactor(
-        ui,
-        hasmultiplesend=False,
-        buffersends=True,
-        clientcontentencoders=encoders,
-    )
-
-    handler = wireprotov2peer.clienthandler(
-        ui, reactor, opener=opener, requestbuilder=requestbuilder
-    )
-
-    url = b'%s/%s' % (apiurl, permission)
-
-    if len(requests) > 1:
-        url += b'/multirequest'
-    else:
-        url += b'/%s' % requests[0][0]
-
-    ui.debug(b'sending %d commands\n' % len(requests))
-    for command, args, f in requests:
-        ui.debug(
-            b'sending command %s: %s\n'
-            % (command, stringutil.pprint(args, indent=2))
-        )
-        assert not list(
-            handler.callcommand(command, args, f, redirect=redirect)
-        )
-
-    # TODO stream this.
-    body = b''.join(map(bytes, handler.flushcommands()))
-
-    # TODO modify user-agent to reflect v2
-    headers = {
-        'Accept': wireprotov2server.FRAMINGTYPE,
-        'Content-Type': wireprotov2server.FRAMINGTYPE,
-    }
-
-    req = requestbuilder(pycompat.strurl(url), body, headers)
-    req.add_unredirected_header('Content-Length', '%d' % len(body))
-
-    try:
-        res = opener.open(req)
-    except urlerr.httperror as e:
-        if e.code == 401:
-            raise error.Abort(_(b'authorization failed'))
-
-        raise
-    except httplib.HTTPException as e:
-        ui.traceback()
-        raise IOError(None, e)
-
-    return handler, res
-
-
 class queuedcommandfuture(pycompat.futures.Future):
     """Wraps result() on command futures to trigger submission on call."""
 
@@ -657,302 +552,6 @@
         return self.result(timeout)
 
 
-@interfaceutil.implementer(repository.ipeercommandexecutor)
-class httpv2executor(object):
-    def __init__(
-        self, ui, opener, requestbuilder, apiurl, descriptor, redirect
-    ):
-        self._ui = ui
-        self._opener = opener
-        self._requestbuilder = requestbuilder
-        self._apiurl = apiurl
-        self._descriptor = descriptor
-        self._redirect = redirect
-        self._sent = False
-        self._closed = False
-        self._neededpermissions = set()
-        self._calls = []
-        self._futures = weakref.WeakSet()
-        self._responseexecutor = None
-        self._responsef = None
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exctype, excvalue, exctb):
-        self.close()
-
-    def callcommand(self, command, args):
-        if self._sent:
-            raise error.ProgrammingError(
-                b'callcommand() cannot be used after commands are sent'
-            )
-
-        if self._closed:
-            raise error.ProgrammingError(
-                b'callcommand() cannot be used after close()'
-            )
-
-        # The service advertises which commands are available. So if we attempt
-        # to call an unknown command or pass an unknown argument, we can screen
-        # for this.
-        if command not in self._descriptor[b'commands']:
-            raise error.ProgrammingError(
-                b'wire protocol command %s is not available' % command
-            )
-
-        cmdinfo = self._descriptor[b'commands'][command]
-        unknownargs = set(args.keys()) - set(cmdinfo.get(b'args', {}))
-
-        if unknownargs:
-            raise error.ProgrammingError(
-                b'wire protocol command %s does not accept argument: %s'
-                % (command, b', '.join(sorted(unknownargs)))
-            )
-
-        self._neededpermissions |= set(cmdinfo[b'permissions'])
-
-        # TODO we /could/ also validate types here, since the API descriptor
-        # includes types...
-
-        f = pycompat.futures.Future()
-
-        # Monkeypatch it so result() triggers sendcommands(), otherwise result()
-        # could deadlock.
-        f.__class__ = queuedcommandfuture
-        f._peerexecutor = self
-
-        self._futures.add(f)
-        self._calls.append((command, args, f))
-
-        return f
-
-    def sendcommands(self):
-        if self._sent:
-            return
-
-        if not self._calls:
-            return
-
-        self._sent = True
-
-        # Unhack any future types so caller sees a clean type and so we
-        # break reference cycle.
-        for f in self._futures:
-            if isinstance(f, queuedcommandfuture):
-                f.__class__ = pycompat.futures.Future
-                f._peerexecutor = None
-
-        # Mark the future as running and filter out cancelled futures.
-        calls = [
-            (command, args, f)
-            for command, args, f in self._calls
-            if f.set_running_or_notify_cancel()
-        ]
-
-        # Clear out references, prevent improper object usage.
-        self._calls = None
-
-        if not calls:
-            return
-
-        permissions = set(self._neededpermissions)
-
-        if b'push' in permissions and b'pull' in permissions:
-            permissions.remove(b'pull')
-
-        if len(permissions) > 1:
-            raise error.RepoError(
-                _(b'cannot make request requiring multiple permissions: %s')
-                % _(b', ').join(sorted(permissions))
-            )
-
-        permission = {
-            b'push': b'rw',
-            b'pull': b'ro',
-        }[permissions.pop()]
-
-        handler, resp = sendv2request(
-            self._ui,
-            self._opener,
-            self._requestbuilder,
-            self._apiurl,
-            permission,
-            calls,
-            self._redirect,
-        )
-
-        # TODO we probably want to validate the HTTP code, media type, etc.
-
-        self._responseexecutor = pycompat.futures.ThreadPoolExecutor(1)
-        self._responsef = self._responseexecutor.submit(
-            self._handleresponse, handler, resp
-        )
-
-    def close(self):
-        if self._closed:
-            return
-
-        self.sendcommands()
-
-        self._closed = True
-
-        if not self._responsef:
-            return
-
-        # TODO ^C here may not result in immediate program termination.
-
-        try:
-            self._responsef.result()
-        finally:
-            self._responseexecutor.shutdown(wait=True)
-            self._responsef = None
-            self._responseexecutor = None
-
-            # If any of our futures are still in progress, mark them as
-            # errored, otherwise a result() could wait indefinitely.
-            for f in self._futures:
-                if not f.done():
-                    f.set_exception(
-                        error.ResponseError(_(b'unfulfilled command response'))
-                    )
-
-            self._futures = None
-
-    def _handleresponse(self, handler, resp):
-        # Called in a thread to read the response.
-
-        while handler.readdata(resp):
-            pass
-
-
-@interfaceutil.implementer(repository.ipeerv2)
-class httpv2peer(object):
-
-    limitedarguments = False
-
-    def __init__(
-        self, ui, repourl, apipath, opener, requestbuilder, apidescriptor
-    ):
-        self.ui = ui
-        self.apidescriptor = apidescriptor
-
-        if repourl.endswith(b'/'):
-            repourl = repourl[:-1]
-
-        self._url = repourl
-        self._apipath = apipath
-        self._apiurl = b'%s/%s' % (repourl, apipath)
-        self._opener = opener
-        self._requestbuilder = requestbuilder
-
-        self._redirect = wireprotov2peer.supportedredirects(ui, apidescriptor)
-
-    # Start of ipeerconnection.
-
-    def url(self):
-        return self._url
-
-    def local(self):
-        return None
-
-    def peer(self):
-        return self
-
-    def canpush(self):
-        # TODO change once implemented.
-        return False
-
-    def close(self):
-        self.ui.note(
-            _(
-                b'(sent %d HTTP requests and %d bytes; '
-                b'received %d bytes in responses)\n'
-            )
-            % (
-                self._opener.requestscount,
-                self._opener.sentbytescount,
-                self._opener.receivedbytescount,
-            )
-        )
-
-    # End of ipeerconnection.
-
-    # Start of ipeercapabilities.
-
-    def capable(self, name):
-        # The capabilities used internally historically map to capabilities
-        # advertised from the "capabilities" wire protocol command. However,
-        # version 2 of that command works differently.
-
-        # Maps to commands that are available.
-        if name in (
-            b'branchmap',
-            b'getbundle',
-            b'known',
-            b'lookup',
-            b'pushkey',
-        ):
-            return True
-
-        # Other concepts.
-        if name in (b'bundle2',):
-            return True
-
-        # Alias command-* to presence of command of that name.
-        if name.startswith(b'command-'):
-            return name[len(b'command-') :] in self.apidescriptor[b'commands']
-
-        return False
-
-    def requirecap(self, name, purpose):
-        if self.capable(name):
-            return
-
-        raise error.CapabilityError(
-            _(
-                b'cannot %s; client or remote repository does not support the '
-                b'\'%s\' capability'
-            )
-            % (purpose, name)
-        )
-
-    # End of ipeercapabilities.
-
-    def _call(self, name, **args):
-        with self.commandexecutor() as e:
-            return e.callcommand(name, args).result()
-
-    def commandexecutor(self):
-        return httpv2executor(
-            self.ui,
-            self._opener,
-            self._requestbuilder,
-            self._apiurl,
-            self.apidescriptor,
-            self._redirect,
-        )
-
-
-# Registry of API service names to metadata about peers that handle it.
-#
-# The following keys are meaningful:
-#
-# init
-#    Callable receiving (ui, repourl, servicepath, opener, requestbuilder,
-#                        apidescriptor) to create a peer.
-#
-# priority
-#    Integer priority for the service. If we could choose from multiple
-#    services, we choose the one with the highest priority.
-API_PEERS = {
-    wireprototypes.HTTP_WIREPROTO_V2: {
-        b'init': httpv2peer,
-        b'priority': 50,
-    },
-}
-
-
 def performhandshake(ui, url, opener, requestbuilder):
     # The handshake is a request to the capabilities command.
 
@@ -963,28 +562,6 @@
 
     args = {}
 
-    # The client advertises support for newer protocols by adding an
-    # X-HgUpgrade-* header with a list of supported APIs and an
-    # X-HgProto-* header advertising which serializing formats it supports.
-    # We only support the HTTP version 2 transport and CBOR responses for
-    # now.
-    advertisev2 = ui.configbool(b'experimental', b'httppeer.advertise-v2')
-
-    if advertisev2:
-        args[b'headers'] = {
-            'X-HgProto-1': 'cbor',
-        }
-
-        args[b'headers'].update(
-            encodevalueinheaders(
-                b' '.join(sorted(API_PEERS)),
-                b'X-HgUpgrade',
-                # We don't know the header limit this early.
-                # So make it small.
-                1024,
-            )
-        )
-
     req, requrl, qs = makev1commandrequest(
         ui, requestbuilder, caps, capable, url, b'capabilities', args
     )
@@ -1004,7 +581,7 @@
     # redirect that drops the query string to "just work."
     try:
         respurl, ct, resp = parsev1commandresponse(
-            ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2
+            ui, url, requrl, qs, resp, compressible=False
         )
     except RedirectedRepoError as e:
         req, requrl, qs = makev1commandrequest(
@@ -1012,7 +589,7 @@
         )
         resp = sendrequest(ui, opener, req)
         respurl, ct, resp = parsev1commandresponse(
-            ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2
+            ui, url, requrl, qs, resp, compressible=False
         )
 
     try:
@@ -1023,29 +600,7 @@
     if not ct.startswith(b'application/mercurial-'):
         raise error.ProgrammingError(b'unexpected content-type: %s' % ct)
 
-    if advertisev2:
-        if ct == b'application/mercurial-cbor':
-            try:
-                info = cborutil.decodeall(rawdata)[0]
-            except cborutil.CBORDecodeError:
-                raise error.Abort(
-                    _(b'error decoding CBOR from remote server'),
-                    hint=_(
-                        b'try again and consider contacting '
-                        b'the server operator'
-                    ),
-                )
-
-        # We got a legacy response. That's fine.
-        elif ct in (b'application/mercurial-0.1', b'application/mercurial-0.2'):
-            info = {b'v1capabilities': set(rawdata.split())}
-
-        else:
-            raise error.RepoError(
-                _(b'unexpected response type from server: %s') % ct
-            )
-    else:
-        info = {b'v1capabilities': set(rawdata.split())}
+    info = {b'v1capabilities': set(rawdata.split())}
 
     return respurl, info
 
@@ -1073,29 +628,6 @@
 
     respurl, info = performhandshake(ui, url, opener, requestbuilder)
 
-    # Given the intersection of APIs that both we and the server support,
-    # sort by their advertised priority and pick the first one.
-    #
-    # TODO consider making this request-based and interface driven. For
-    # example, the caller could say "I want a peer that does X." It's quite
-    # possible that not all peers would do that. Since we know the service
-    # capabilities, we could filter out services not meeting the
-    # requirements. Possibly by consulting the interfaces defined by the
-    # peer type.
-    apipeerchoices = set(info.get(b'apis', {}).keys()) & set(API_PEERS.keys())
-
-    preferredchoices = sorted(
-        apipeerchoices, key=lambda x: API_PEERS[x][b'priority'], reverse=True
-    )
-
-    for service in preferredchoices:
-        apipath = b'%s/%s' % (info[b'apibase'].rstrip(b'/'), service)
-
-        return API_PEERS[service][b'init'](
-            ui, respurl, apipath, opener, requestbuilder, info[b'apis'][service]
-        )
-
-    # Failed to construct an API peer. Fall back to legacy.
     return httppeer(
         ui, path, respurl, opener, requestbuilder, info[b'v1capabilities']
     )
--- a/mercurial/sshpeer.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/sshpeer.py	Tue Dec 07 16:44:22 2021 +0100
@@ -16,7 +16,6 @@
     error,
     pycompat,
     util,
-    wireprotoserver,
     wireprototypes,
     wireprotov1peer,
     wireprotov1server,
@@ -288,10 +287,6 @@
     # Generate a random token to help identify responses to version 2
     # upgrade request.
     token = pycompat.sysbytes(str(uuid.uuid4()))
-    upgradecaps = [
-        (b'proto', wireprotoserver.SSHV2),
-    ]
-    upgradecaps = util.urlreq.urlencode(upgradecaps)
 
     try:
         pairsarg = b'%s-%s' % (b'0' * 40, b'0' * 40)
@@ -302,11 +297,6 @@
             pairsarg,
         ]
 
-        # Request upgrade to version 2 if configured.
-        if ui.configbool(b'experimental', b'sshpeer.advertise-v2'):
-            ui.debug(b'sending upgrade request: %s %s\n' % (token, upgradecaps))
-            handshake.insert(0, b'upgrade %s %s\n' % (token, upgradecaps))
-
         if requestlog:
             ui.debug(b'devel-peer-request: hello+between\n')
             ui.debug(b'devel-peer-request:   pairs: %d bytes\n' % len(pairsarg))
@@ -365,24 +355,6 @@
             if l.startswith(b'capabilities:'):
                 caps.update(l[:-1].split(b':')[1].split())
                 break
-    elif protoname == wireprotoserver.SSHV2:
-        # We see a line with number of bytes to follow and then a value
-        # looking like ``capabilities: *``.
-        line = stdout.readline()
-        try:
-            valuelen = int(line)
-        except ValueError:
-            badresponse()
-
-        capsline = stdout.read(valuelen)
-        if not capsline.startswith(b'capabilities: '):
-            badresponse()
-
-        ui.debug(b'remote: %s\n' % capsline)
-
-        caps.update(capsline.split(b':')[1].split())
-        # Trailing newline.
-        stdout.read(1)
 
     # Error if we couldn't find capabilities, this means:
     #
@@ -601,14 +573,6 @@
             self._readerr()
 
 
-class sshv2peer(sshv1peer):
-    """A peer that speakers version 2 of the transport protocol."""
-
-    # Currently version 2 is identical to version 1 post handshake.
-    # And handshake is performed before the peer is instantiated. So
-    # we need no custom code.
-
-
 def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True):
     """Make a peer instance from existing pipes.
 
@@ -640,17 +604,6 @@
             caps,
             autoreadstderr=autoreadstderr,
         )
-    elif protoname == wireprototypes.SSHV2:
-        return sshv2peer(
-            ui,
-            path,
-            proc,
-            stdin,
-            stdout,
-            stderr,
-            caps,
-            autoreadstderr=autoreadstderr,
-        )
     else:
         _cleanuppipes(ui, stdout, stdin, stderr, warn=None)
         raise error.RepoError(
--- a/mercurial/wireprotoserver.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/wireprotoserver.py	Tue Dec 07 16:44:22 2021 +0100
@@ -18,11 +18,9 @@
     util,
     wireprototypes,
     wireprotov1server,
-    wireprotov2server,
 )
 from .interfaces import util as interfaceutil
 from .utils import (
-    cborutil,
     compression,
     stringutil,
 )
@@ -39,7 +37,6 @@
 HGERRTYPE = b'application/hg-error'
 
 SSHV1 = wireprototypes.SSHV1
-SSHV2 = wireprototypes.SSHV2
 
 
 def decodevaluefromheaders(req, headerprefix):
@@ -244,97 +241,6 @@
     return True
 
 
-def _availableapis(repo):
-    apis = set()
-
-    # Registered APIs are made available via config options of the name of
-    # the protocol.
-    for k, v in API_HANDLERS.items():
-        section, option = v[b'config']  # pytype: disable=attribute-error
-        if repo.ui.configbool(section, option):
-            apis.add(k)
-
-    return apis
-
-
-def handlewsgiapirequest(rctx, req, res, checkperm):
-    """Handle requests to /api/*."""
-    assert req.dispatchparts[0] == b'api'
-
-    repo = rctx.repo
-
-    # This whole URL space is experimental for now. But we want to
-    # reserve the URL space. So, 404 all URLs if the feature isn't enabled.
-    if not repo.ui.configbool(b'experimental', b'web.apiserver'):
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'Experimental API server endpoint not enabled'))
-        return
-
-    # The URL space is /api/<protocol>/*. The structure of URLs under varies
-    # by <protocol>.
-
-    availableapis = _availableapis(repo)
-
-    # Requests to /api/ list available APIs.
-    if req.dispatchparts == [b'api']:
-        res.status = b'200 OK'
-        res.headers[b'Content-Type'] = b'text/plain'
-        lines = [
-            _(
-                b'APIs can be accessed at /api/<name>, where <name> can be '
-                b'one of the following:\n'
-            )
-        ]
-        if availableapis:
-            lines.extend(sorted(availableapis))
-        else:
-            lines.append(_(b'(no available APIs)\n'))
-        res.setbodybytes(b'\n'.join(lines))
-        return
-
-    proto = req.dispatchparts[1]
-
-    if proto not in API_HANDLERS:
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(
-            _(b'Unknown API: %s\nKnown APIs: %s')
-            % (proto, b', '.join(sorted(availableapis)))
-        )
-        return
-
-    if proto not in availableapis:
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'API %s not enabled\n') % proto)
-        return
-
-    API_HANDLERS[proto][b'handler'](
-        rctx, req, res, checkperm, req.dispatchparts[2:]
-    )
-
-
-# Maps API name to metadata so custom API can be registered.
-# Keys are:
-#
-# config
-#    Config option that controls whether service is enabled.
-# handler
-#    Callable receiving (rctx, req, res, checkperm, urlparts) that is called
-#    when a request to this API is received.
-# apidescriptor
-#    Callable receiving (req, repo) that is called to obtain an API
-#    descriptor for this service. The response must be serializable to CBOR.
-API_HANDLERS = {
-    wireprotov2server.HTTP_WIREPROTO_V2: {
-        b'config': (b'experimental', b'web.api.http-v2'),
-        b'handler': wireprotov2server.handlehttpv2request,
-        b'apidescriptor': wireprotov2server.httpv2apidescriptor,
-    },
-}
-
-
 def _httpresponsetype(ui, proto, prefer_uncompressed):
     """Determine the appropriate response type and compression settings.
 
@@ -371,55 +277,6 @@
     return HGTYPE, util.compengines[b'zlib'], opts
 
 
-def processcapabilitieshandshake(repo, req, res, proto):
-    """Called during a ?cmd=capabilities request.
-
-    If the client is advertising support for a newer protocol, we send
-    a CBOR response with information about available services. If no
-    advertised services are available, we don't handle the request.
-    """
-    # Fall back to old behavior unless the API server is enabled.
-    if not repo.ui.configbool(b'experimental', b'web.apiserver'):
-        return False
-
-    clientapis = decodevaluefromheaders(req, b'X-HgUpgrade')
-    protocaps = decodevaluefromheaders(req, b'X-HgProto')
-    if not clientapis or not protocaps:
-        return False
-
-    # We currently only support CBOR responses.
-    protocaps = set(protocaps.split(b' '))
-    if b'cbor' not in protocaps:
-        return False
-
-    descriptors = {}
-
-    for api in sorted(set(clientapis.split()) & _availableapis(repo)):
-        handler = API_HANDLERS[api]
-
-        descriptorfn = handler.get(b'apidescriptor')
-        if not descriptorfn:
-            continue
-
-        descriptors[api] = descriptorfn(req, repo)
-
-    v1caps = wireprotov1server.dispatch(repo, proto, b'capabilities')
-    assert isinstance(v1caps, wireprototypes.bytesresponse)
-
-    m = {
-        # TODO allow this to be configurable.
-        b'apibase': b'api/',
-        b'apis': descriptors,
-        b'v1capabilities': v1caps.data,
-    }
-
-    res.status = b'200 OK'
-    res.headers[b'Content-Type'] = b'application/mercurial-cbor'
-    res.setbodybytes(b''.join(cborutil.streamencode(m)))
-
-    return True
-
-
 def _callhttp(repo, req, res, proto, cmd):
     # Avoid cycle involving hg module.
     from .hgweb import common as hgwebcommon
@@ -461,13 +318,6 @@
 
     proto.checkperm(wireprotov1server.commands[cmd].permission)
 
-    # Possibly handle a modern client wanting to switch protocols.
-    if cmd == b'capabilities' and processcapabilitieshandshake(
-        repo, req, res, proto
-    ):
-
-        return
-
     rsp = wireprotov1server.dispatch(repo, proto, cmd)
 
     if isinstance(rsp, bytes):
@@ -596,17 +446,6 @@
         pass
 
 
-class sshv2protocolhandler(sshv1protocolhandler):
-    """Protocol handler for version 2 of the SSH protocol."""
-
-    @property
-    def name(self):
-        return wireprototypes.SSHV2
-
-    def addcapabilities(self, repo, caps):
-        return caps
-
-
 def _runsshserver(ui, repo, fin, fout, ev):
     # This function operates like a state machine of sorts. The following
     # states are defined:
@@ -616,19 +455,6 @@
     #    new lines. These commands are processed in this state, one command
     #    after the other.
     #
-    # protov2-serving
-    #    Server is in protocol version 2 serving mode.
-    #
-    # upgrade-initial
-    #    The server is going to process an upgrade request.
-    #
-    # upgrade-v2-filter-legacy-handshake
-    #    The protocol is being upgraded to version 2. The server is expecting
-    #    the legacy handshake from version 1.
-    #
-    # upgrade-v2-finish
-    #    The upgrade to version 2 of the protocol is imminent.
-    #
     # shutdown
     #    The server is shutting down, possibly in reaction to a client event.
     #
@@ -637,32 +463,9 @@
     # protov1-serving -> shutdown
     #    When server receives an empty request or encounters another
     #    error.
-    #
-    # protov1-serving -> upgrade-initial
-    #    An upgrade request line was seen.
-    #
-    # upgrade-initial -> upgrade-v2-filter-legacy-handshake
-    #    Upgrade to version 2 in progress. Server is expecting to
-    #    process a legacy handshake.
-    #
-    # upgrade-v2-filter-legacy-handshake -> shutdown
-    #    Client did not fulfill upgrade handshake requirements.
-    #
-    # upgrade-v2-filter-legacy-handshake -> upgrade-v2-finish
-    #    Client fulfilled version 2 upgrade requirements. Finishing that
-    #    upgrade.
-    #
-    # upgrade-v2-finish -> protov2-serving
-    #    Protocol upgrade to version 2 complete. Server can now speak protocol
-    #    version 2.
-    #
-    # protov2-serving -> protov1-serving
-    #    Ths happens by default since protocol version 2 is the same as
-    #    version 1 except for the handshake.
 
     state = b'protov1-serving'
     proto = sshv1protocolhandler(ui, fin, fout)
-    protoswitched = False
 
     while not ev.is_set():
         if state == b'protov1-serving':
@@ -674,21 +477,6 @@
                 state = b'shutdown'
                 continue
 
-            # It looks like a protocol upgrade request. Transition state to
-            # handle it.
-            if request.startswith(b'upgrade '):
-                if protoswitched:
-                    _sshv1respondooberror(
-                        fout,
-                        ui.ferr,
-                        b'cannot upgrade protocols multiple times',
-                    )
-                    state = b'shutdown'
-                    continue
-
-                state = b'upgrade-initial'
-                continue
-
             available = wireprotov1server.commands.commandavailable(
                 request, proto
             )
@@ -724,108 +512,6 @@
                     b'wire protocol command: %s' % rsp
                 )
 
-        # For now, protocol version 2 serving just goes back to version 1.
-        elif state == b'protov2-serving':
-            state = b'protov1-serving'
-            continue
-
-        elif state == b'upgrade-initial':
-            # We should never transition into this state if we've switched
-            # protocols.
-            assert not protoswitched
-            assert proto.name == wireprototypes.SSHV1
-
-            # Expected: upgrade <token> <capabilities>
-            # If we get something else, the request is malformed. It could be
-            # from a future client that has altered the upgrade line content.
-            # We treat this as an unknown command.
-            try:
-                token, caps = request.split(b' ')[1:]
-            except ValueError:
-                _sshv1respondbytes(fout, b'')
-                state = b'protov1-serving'
-                continue
-
-            # Send empty response if we don't support upgrading protocols.
-            if not ui.configbool(b'experimental', b'sshserver.support-v2'):
-                _sshv1respondbytes(fout, b'')
-                state = b'protov1-serving'
-                continue
-
-            try:
-                caps = urlreq.parseqs(caps)
-            except ValueError:
-                _sshv1respondbytes(fout, b'')
-                state = b'protov1-serving'
-                continue
-
-            # We don't see an upgrade request to protocol version 2. Ignore
-            # the upgrade request.
-            wantedprotos = caps.get(b'proto', [b''])[0]
-            if SSHV2 not in wantedprotos:
-                _sshv1respondbytes(fout, b'')
-                state = b'protov1-serving'
-                continue
-
-            # It looks like we can honor this upgrade request to protocol 2.
-            # Filter the rest of the handshake protocol request lines.
-            state = b'upgrade-v2-filter-legacy-handshake'
-            continue
-
-        elif state == b'upgrade-v2-filter-legacy-handshake':
-            # Client should have sent legacy handshake after an ``upgrade``
-            # request. Expected lines:
-            #
-            #    hello
-            #    between
-            #    pairs 81
-            #    0000...-0000...
-
-            ok = True
-            for line in (b'hello', b'between', b'pairs 81'):
-                request = fin.readline()[:-1]
-
-                if request != line:
-                    _sshv1respondooberror(
-                        fout,
-                        ui.ferr,
-                        b'malformed handshake protocol: missing %s' % line,
-                    )
-                    ok = False
-                    state = b'shutdown'
-                    break
-
-            if not ok:
-                continue
-
-            request = fin.read(81)
-            if request != b'%s-%s' % (b'0' * 40, b'0' * 40):
-                _sshv1respondooberror(
-                    fout,
-                    ui.ferr,
-                    b'malformed handshake protocol: '
-                    b'missing between argument value',
-                )
-                state = b'shutdown'
-                continue
-
-            state = b'upgrade-v2-finish'
-            continue
-
-        elif state == b'upgrade-v2-finish':
-            # Send the upgrade response.
-            fout.write(b'upgraded %s %s\n' % (token, SSHV2))
-            servercaps = wireprotov1server.capabilities(repo, proto)
-            rsp = b'capabilities: %s' % servercaps.data
-            fout.write(b'%d\n%s\n' % (len(rsp), rsp))
-            fout.flush()
-
-            proto = sshv2protocolhandler(ui, fin, fout)
-            protoswitched = True
-
-            state = b'protov2-serving'
-            continue
-
         elif state == b'shutdown':
             break
 
--- a/mercurial/wireprototypes.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/wireprototypes.py	Tue Dec 07 16:44:22 2021 +0100
@@ -21,10 +21,6 @@
 
 # Names of the SSH protocol implementations.
 SSHV1 = b'ssh-v1'
-# These are advertised over the wire. Increment the counters at the end
-# to reflect BC breakages.
-SSHV2 = b'exp-ssh-v2-0003'
-HTTP_WIREPROTO_V2 = b'exp-http-v2-0003'
 
 NARROWCAP = b'exp-narrow-1'
 ELLIPSESCAP1 = b'exp-ellipses-1'
@@ -37,19 +33,10 @@
         b'transport': b'ssh',
         b'version': 1,
     },
-    SSHV2: {
-        b'transport': b'ssh',
-        # TODO mark as version 2 once all commands are implemented.
-        b'version': 1,
-    },
     b'http-v1': {
         b'transport': b'http',
         b'version': 1,
     },
-    HTTP_WIREPROTO_V2: {
-        b'transport': b'http',
-        b'version': 2,
-    },
 }
 
 
--- a/mercurial/wireprotov1server.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/mercurial/wireprotov1server.py	Tue Dec 07 16:44:22 2021 +0100
@@ -147,12 +147,6 @@
         k for k, v in wireprototypes.TRANSPORTS.items() if v[b'version'] == 1
     }
 
-    # Because SSHv2 is a mirror of SSHv1, we allow "batch" commands through to
-    # SSHv2.
-    # TODO undo this hack when SSH is using the unified frame protocol.
-    if name == b'batch':
-        transports.add(wireprototypes.SSHV2)
-
     if permission not in (b'push', b'pull'):
         raise error.ProgrammingError(
             b'invalid wire protocol permission; '
--- a/mercurial/wireprotov2peer.py	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,576 +0,0 @@
-# wireprotov2peer.py - client side code for wire protocol version 2
-#
-# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from __future__ import absolute_import
-
-import threading
-
-from .i18n import _
-from . import (
-    encoding,
-    error,
-    pycompat,
-    sslutil,
-    url as urlmod,
-    util,
-    wireprotoframing,
-    wireprototypes,
-)
-from .utils import cborutil
-
-
-def formatrichmessage(atoms):
-    """Format an encoded message from the framing protocol."""
-
-    chunks = []
-
-    for atom in atoms:
-        msg = _(atom[b'msg'])
-
-        if b'args' in atom:
-            msg = msg % tuple(atom[b'args'])
-
-        chunks.append(msg)
-
-    return b''.join(chunks)
-
-
-SUPPORTED_REDIRECT_PROTOCOLS = {
-    b'http',
-    b'https',
-}
-
-SUPPORTED_CONTENT_HASHES = {
-    b'sha1',
-    b'sha256',
-}
-
-
-def redirecttargetsupported(ui, target):
-    """Determine whether a redirect target entry is supported.
-
-    ``target`` should come from the capabilities data structure emitted by
-    the server.
-    """
-    if target.get(b'protocol') not in SUPPORTED_REDIRECT_PROTOCOLS:
-        ui.note(
-            _(b'(remote redirect target %s uses unsupported protocol: %s)\n')
-            % (target[b'name'], target.get(b'protocol', b''))
-        )
-        return False
-
-    if target.get(b'snirequired') and not sslutil.hassni:
-        ui.note(
-            _(b'(redirect target %s requires SNI, which is unsupported)\n')
-            % target[b'name']
-        )
-        return False
-
-    if b'tlsversions' in target:
-        tlsversions = set(target[b'tlsversions'])
-        supported = set()
-
-        for v in sslutil.supportedprotocols:
-            assert v.startswith(b'tls')
-            supported.add(v[3:])
-
-        if not tlsversions & supported:
-            ui.note(
-                _(
-                    b'(remote redirect target %s requires unsupported TLS '
-                    b'versions: %s)\n'
-                )
-                % (target[b'name'], b', '.join(sorted(tlsversions)))
-            )
-            return False
-
-    ui.note(_(b'(remote redirect target %s is compatible)\n') % target[b'name'])
-
-    return True
-
-
-def supportedredirects(ui, apidescriptor):
-    """Resolve the "redirect" command request key given an API descriptor.
-
-    Given an API descriptor returned by the server, returns a data structure
-    that can be used in hte "redirect" field of command requests to advertise
-    support for compatible redirect targets.
-
-    Returns None if no redirect targets are remotely advertised or if none are
-    supported.
-    """
-    if not apidescriptor or b'redirect' not in apidescriptor:
-        return None
-
-    targets = [
-        t[b'name']
-        for t in apidescriptor[b'redirect'][b'targets']
-        if redirecttargetsupported(ui, t)
-    ]
-
-    hashes = [
-        h
-        for h in apidescriptor[b'redirect'][b'hashes']
-        if h in SUPPORTED_CONTENT_HASHES
-    ]
-
-    return {
-        b'targets': targets,
-        b'hashes': hashes,
-    }
-
-
-class commandresponse(object):
-    """Represents the response to a command request.
-
-    Instances track the state of the command and hold its results.
-
-    An external entity is required to update the state of the object when
-    events occur.
-    """
-
-    def __init__(self, requestid, command, fromredirect=False):
-        self.requestid = requestid
-        self.command = command
-        self.fromredirect = fromredirect
-
-        # Whether all remote input related to this command has been
-        # received.
-        self._inputcomplete = False
-
-        # We have a lock that is acquired when important object state is
-        # mutated. This is to prevent race conditions between 1 thread
-        # sending us new data and another consuming it.
-        self._lock = threading.RLock()
-
-        # An event is set when state of the object changes. This event
-        # is waited on by the generator emitting objects.
-        self._serviceable = threading.Event()
-
-        self._pendingevents = []
-        self._pendingerror = None
-        self._decoder = cborutil.bufferingdecoder()
-        self._seeninitial = False
-        self._redirect = None
-
-    def _oninputcomplete(self):
-        with self._lock:
-            self._inputcomplete = True
-            self._serviceable.set()
-
-    def _onresponsedata(self, data):
-        available, readcount, wanted = self._decoder.decode(data)
-
-        if not available:
-            return
-
-        with self._lock:
-            for o in self._decoder.getavailable():
-                if not self._seeninitial and not self.fromredirect:
-                    self._handleinitial(o)
-                    continue
-
-                # We should never see an object after a content redirect,
-                # as the spec says the main status object containing the
-                # content redirect is the only object in the stream. Fail
-                # if we see a misbehaving server.
-                if self._redirect:
-                    raise error.Abort(
-                        _(
-                            b'received unexpected response data '
-                            b'after content redirect; the remote is '
-                            b'buggy'
-                        )
-                    )
-
-                self._pendingevents.append(o)
-
-            self._serviceable.set()
-
-    def _onerror(self, e):
-        self._pendingerror = e
-
-        with self._lock:
-            self._serviceable.set()
-
-    def _handleinitial(self, o):
-        self._seeninitial = True
-        if o[b'status'] == b'ok':
-            return
-
-        elif o[b'status'] == b'redirect':
-            l = o[b'location']
-            self._redirect = wireprototypes.alternatelocationresponse(
-                url=l[b'url'],
-                mediatype=l[b'mediatype'],
-                size=l.get(b'size'),
-                fullhashes=l.get(b'fullhashes'),
-                fullhashseed=l.get(b'fullhashseed'),
-                serverdercerts=l.get(b'serverdercerts'),
-                servercadercerts=l.get(b'servercadercerts'),
-            )
-            return
-
-        atoms = [{b'msg': o[b'error'][b'message']}]
-        if b'args' in o[b'error']:
-            atoms[0][b'args'] = o[b'error'][b'args']
-
-        raise error.RepoError(formatrichmessage(atoms))
-
-    def objects(self):
-        """Obtained decoded objects from this response.
-
-        This is a generator of data structures that were decoded from the
-        command response.
-
-        Obtaining the next member of the generator may block due to waiting
-        on external data to become available.
-
-        If the server encountered an error in the middle of serving the data
-        or if another error occurred, an exception may be raised when
-        advancing the generator.
-        """
-        while True:
-            # TODO this can infinite loop if self._inputcomplete is never
-            # set. We likely want to tie the lifetime of this object/state
-            # to that of the background thread receiving frames and updating
-            # our state.
-            self._serviceable.wait(1.0)
-
-            if self._pendingerror:
-                raise self._pendingerror
-
-            with self._lock:
-                self._serviceable.clear()
-
-                # Make copies because objects could be mutated during
-                # iteration.
-                stop = self._inputcomplete
-                pending = list(self._pendingevents)
-                self._pendingevents[:] = []
-
-            for o in pending:
-                yield o
-
-            if stop:
-                break
-
-
-class clienthandler(object):
-    """Object to handle higher-level client activities.
-
-    The ``clientreactor`` is used to hold low-level state about the frame-based
-    protocol, such as which requests and streams are active. This type is used
-    for higher-level operations, such as reading frames from a socket, exposing
-    and managing a higher-level primitive for representing command responses,
-    etc. This class is what peers should probably use to bridge wire activity
-    with the higher-level peer API.
-    """
-
-    def __init__(
-        self, ui, clientreactor, opener=None, requestbuilder=util.urlreq.request
-    ):
-        self._ui = ui
-        self._reactor = clientreactor
-        self._requests = {}
-        self._futures = {}
-        self._responses = {}
-        self._redirects = []
-        self._frameseof = False
-        self._opener = opener or urlmod.opener(ui)
-        self._requestbuilder = requestbuilder
-
-    def callcommand(self, command, args, f, redirect=None):
-        """Register a request to call a command.
-
-        Returns an iterable of frames that should be sent over the wire.
-        """
-        request, action, meta = self._reactor.callcommand(
-            command, args, redirect=redirect
-        )
-
-        if action != b'noop':
-            raise error.ProgrammingError(b'%s not yet supported' % action)
-
-        rid = request.requestid
-        self._requests[rid] = request
-        self._futures[rid] = f
-        # TODO we need some kind of lifetime on response instances otherwise
-        # objects() may deadlock.
-        self._responses[rid] = commandresponse(rid, command)
-
-        return iter(())
-
-    def flushcommands(self):
-        """Flush all queued commands.
-
-        Returns an iterable of frames that should be sent over the wire.
-        """
-        action, meta = self._reactor.flushcommands()
-
-        if action != b'sendframes':
-            raise error.ProgrammingError(b'%s not yet supported' % action)
-
-        return meta[b'framegen']
-
-    def readdata(self, framefh):
-        """Attempt to read data and do work.
-
-        Returns None if no data was read. Presumably this means we're
-        done with all read I/O.
-        """
-        if not self._frameseof:
-            frame = wireprotoframing.readframe(framefh)
-            if frame is None:
-                # TODO tell reactor?
-                self._frameseof = True
-            else:
-                self._ui.debug(b'received %r\n' % frame)
-                self._processframe(frame)
-
-        # Also try to read the first redirect.
-        if self._redirects:
-            if not self._processredirect(*self._redirects[0]):
-                self._redirects.pop(0)
-
-        if self._frameseof and not self._redirects:
-            return None
-
-        return True
-
-    def _processframe(self, frame):
-        """Process a single read frame."""
-
-        action, meta = self._reactor.onframerecv(frame)
-
-        if action == b'error':
-            e = error.RepoError(meta[b'message'])
-
-            if frame.requestid in self._responses:
-                self._responses[frame.requestid]._oninputcomplete()
-
-            if frame.requestid in self._futures:
-                self._futures[frame.requestid].set_exception(e)
-                del self._futures[frame.requestid]
-            else:
-                raise e
-
-            return
-        elif action == b'noop':
-            return
-        elif action == b'responsedata':
-            # Handled below.
-            pass
-        else:
-            raise error.ProgrammingError(b'action not handled: %s' % action)
-
-        if frame.requestid not in self._requests:
-            raise error.ProgrammingError(
-                b'received frame for unknown request; this is either a bug in '
-                b'the clientreactor not screening for this or this instance was '
-                b'never told about this request: %r' % frame
-            )
-
-        response = self._responses[frame.requestid]
-
-        if action == b'responsedata':
-            # Any failures processing this frame should bubble up to the
-            # future tracking the request.
-            try:
-                self._processresponsedata(frame, meta, response)
-            except BaseException as e:
-                # If an exception occurs before the future is resolved,
-                # fail the future. Otherwise, we stuff the exception on
-                # the response object so it can be raised during objects()
-                # iteration. If nothing is consuming objects(), we could
-                # silently swallow this exception. That's a risk we'll have to
-                # take.
-                if frame.requestid in self._futures:
-                    self._futures[frame.requestid].set_exception(e)
-                    del self._futures[frame.requestid]
-                    response._oninputcomplete()
-                else:
-                    response._onerror(e)
-        else:
-            raise error.ProgrammingError(
-                b'unhandled action from clientreactor: %s' % action
-            )
-
-    def _processresponsedata(self, frame, meta, response):
-        # This can raise. The caller can handle it.
-        response._onresponsedata(meta[b'data'])
-
-        # We need to be careful about resolving futures prematurely. If a
-        # response is a redirect response, resolving the future before the
-        # redirect is processed would result in the consumer seeing an
-        # empty stream of objects, since they'd be consuming our
-        # response.objects() instead of the redirect's response.objects().
-        #
-        # Our strategy is to not resolve/finish the request until either
-        # EOS occurs or until the initial response object is fully received.
-
-        # Always react to eos.
-        if meta[b'eos']:
-            response._oninputcomplete()
-            del self._requests[frame.requestid]
-
-        # Not EOS but we haven't decoded the initial response object yet.
-        # Return and wait for more data.
-        elif not response._seeninitial:
-            return
-
-        # The specification says no objects should follow the initial/redirect
-        # object. So it should be safe to handle the redirect object if one is
-        # decoded, without having to wait for EOS.
-        if response._redirect:
-            self._followredirect(frame.requestid, response._redirect)
-            return
-
-        # If the command has a decoder, we wait until all input has been
-        # received before resolving the future. Otherwise we resolve the
-        # future immediately.
-        if frame.requestid not in self._futures:
-            return
-
-        if response.command not in COMMAND_DECODERS:
-            self._futures[frame.requestid].set_result(response.objects())
-            del self._futures[frame.requestid]
-        elif response._inputcomplete:
-            decoded = COMMAND_DECODERS[response.command](response.objects())
-            self._futures[frame.requestid].set_result(decoded)
-            del self._futures[frame.requestid]
-
-    def _followredirect(self, requestid, redirect):
-        """Called to initiate redirect following for a request."""
-        self._ui.note(_(b'(following redirect to %s)\n') % redirect.url)
-
-        # TODO handle framed responses.
-        if redirect.mediatype != b'application/mercurial-cbor':
-            raise error.Abort(
-                _(b'cannot handle redirects for the %s media type')
-                % redirect.mediatype
-            )
-
-        if redirect.fullhashes:
-            self._ui.warn(
-                _(
-                    b'(support for validating hashes on content '
-                    b'redirects not supported)\n'
-                )
-            )
-
-        if redirect.serverdercerts or redirect.servercadercerts:
-            self._ui.warn(
-                _(
-                    b'(support for pinning server certificates on '
-                    b'content redirects not supported)\n'
-                )
-            )
-
-        headers = {
-            'Accept': redirect.mediatype,
-        }
-
-        req = self._requestbuilder(pycompat.strurl(redirect.url), None, headers)
-
-        try:
-            res = self._opener.open(req)
-        except util.urlerr.httperror as e:
-            if e.code == 401:
-                raise error.Abort(_(b'authorization failed'))
-            raise
-        except util.httplib.HTTPException as e:
-            self._ui.debug(b'http error requesting %s\n' % req.get_full_url())
-            self._ui.traceback()
-            raise IOError(None, e)
-
-        urlmod.wrapresponse(res)
-
-        # The existing response object is associated with frame data. Rather
-        # than try to normalize its state, just create a new object.
-        oldresponse = self._responses[requestid]
-        self._responses[requestid] = commandresponse(
-            requestid, oldresponse.command, fromredirect=True
-        )
-
-        self._redirects.append((requestid, res))
-
-    def _processredirect(self, rid, res):
-        """Called to continue processing a response from a redirect.
-
-        Returns a bool indicating if the redirect is still serviceable.
-        """
-        response = self._responses[rid]
-
-        try:
-            data = res.read(32768)
-            response._onresponsedata(data)
-
-            # We're at end of stream.
-            if not data:
-                response._oninputcomplete()
-
-            if rid not in self._futures:
-                return bool(data)
-
-            if response.command not in COMMAND_DECODERS:
-                self._futures[rid].set_result(response.objects())
-                del self._futures[rid]
-            elif response._inputcomplete:
-                decoded = COMMAND_DECODERS[response.command](response.objects())
-                self._futures[rid].set_result(decoded)
-                del self._futures[rid]
-
-            return bool(data)
-
-        except BaseException as e:
-            self._futures[rid].set_exception(e)
-            del self._futures[rid]
-            response._oninputcomplete()
-            return False
-
-
-def decodebranchmap(objs):
-    # Response should be a single CBOR map of branch name to array of nodes.
-    bm = next(objs)
-
-    return {encoding.tolocal(k): v for k, v in bm.items()}
-
-
-def decodeheads(objs):
-    # Array of node bytestrings.
-    return next(objs)
-
-
-def decodeknown(objs):
-    # Bytestring where each byte is a 0 or 1.
-    raw = next(objs)
-
-    return [True if raw[i : i + 1] == b'1' else False for i in range(len(raw))]
-
-
-def decodelistkeys(objs):
-    # Map with bytestring keys and values.
-    return next(objs)
-
-
-def decodelookup(objs):
-    return next(objs)
-
-
-def decodepushkey(objs):
-    return next(objs)
-
-
-COMMAND_DECODERS = {
-    b'branchmap': decodebranchmap,
-    b'heads': decodeheads,
-    b'known': decodeknown,
-    b'listkeys': decodelistkeys,
-    b'lookup': decodelookup,
-    b'pushkey': decodepushkey,
-}
--- a/mercurial/wireprotov2server.py	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1617 +0,0 @@
-# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
-# Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from __future__ import absolute_import
-
-import collections
-import contextlib
-
-from .i18n import _
-from .node import hex
-from . import (
-    discovery,
-    encoding,
-    error,
-    match as matchmod,
-    narrowspec,
-    pycompat,
-    streamclone,
-    templatefilters,
-    util,
-    wireprotoframing,
-    wireprototypes,
-)
-from .interfaces import util as interfaceutil
-from .utils import (
-    cborutil,
-    hashutil,
-    stringutil,
-)
-
-FRAMINGTYPE = b'application/mercurial-exp-framing-0006'
-
-HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
-
-COMMANDS = wireprototypes.commanddict()
-
-# Value inserted into cache key computation function. Change the value to
-# force new cache keys for every command request. This should be done when
-# there is a change to how caching works, etc.
-GLOBAL_CACHE_VERSION = 1
-
-
-def handlehttpv2request(rctx, req, res, checkperm, urlparts):
-    from .hgweb import common as hgwebcommon
-
-    # URL space looks like: <permissions>/<command>, where <permission> can
-    # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
-
-    # Root URL does nothing meaningful... yet.
-    if not urlparts:
-        res.status = b'200 OK'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'HTTP version 2 API handler'))
-        return
-
-    if len(urlparts) == 1:
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(
-            _(b'do not know how to process %s\n') % req.dispatchpath
-        )
-        return
-
-    permission, command = urlparts[0:2]
-
-    if permission not in (b'ro', b'rw'):
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'unknown permission: %s') % permission)
-        return
-
-    if req.method != b'POST':
-        res.status = b'405 Method Not Allowed'
-        res.headers[b'Allow'] = b'POST'
-        res.setbodybytes(_(b'commands require POST requests'))
-        return
-
-    # At some point we'll want to use our own API instead of recycling the
-    # behavior of version 1 of the wire protocol...
-    # TODO return reasonable responses - not responses that overload the
-    # HTTP status line message for error reporting.
-    try:
-        checkperm(rctx, req, b'pull' if permission == b'ro' else b'push')
-    except hgwebcommon.ErrorResponse as e:
-        res.status = hgwebcommon.statusmessage(
-            e.code, stringutil.forcebytestr(e)
-        )
-        for k, v in e.headers:
-            res.headers[k] = v
-        res.setbodybytes(b'permission denied')
-        return
-
-    # We have a special endpoint to reflect the request back at the client.
-    if command == b'debugreflect':
-        _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
-        return
-
-    # Extra commands that we handle that aren't really wire protocol
-    # commands. Think extra hard before making this hackery available to
-    # extension.
-    extracommands = {b'multirequest'}
-
-    if command not in COMMANDS and command not in extracommands:
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'unknown wire protocol command: %s\n') % command)
-        return
-
-    repo = rctx.repo
-    ui = repo.ui
-
-    proto = httpv2protocolhandler(req, ui)
-
-    if (
-        not COMMANDS.commandavailable(command, proto)
-        and command not in extracommands
-    ):
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'invalid wire protocol command: %s') % command)
-        return
-
-    # TODO consider cases where proxies may add additional Accept headers.
-    if req.headers.get(b'Accept') != FRAMINGTYPE:
-        res.status = b'406 Not Acceptable'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(
-            _(b'client MUST specify Accept header with value: %s\n')
-            % FRAMINGTYPE
-        )
-        return
-
-    if req.headers.get(b'Content-Type') != FRAMINGTYPE:
-        res.status = b'415 Unsupported Media Type'
-        # TODO we should send a response with appropriate media type,
-        # since client does Accept it.
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(
-            _(b'client MUST send Content-Type header with value: %s\n')
-            % FRAMINGTYPE
-        )
-        return
-
-    _processhttpv2request(ui, repo, req, res, permission, command, proto)
-
-
-def _processhttpv2reflectrequest(ui, repo, req, res):
-    """Reads unified frame protocol request and dumps out state to client.
-
-    This special endpoint can be used to help debug the wire protocol.
-
-    Instead of routing the request through the normal dispatch mechanism,
-    we instead read all frames, decode them, and feed them into our state
-    tracker. We then dump the log of all that activity back out to the
-    client.
-    """
-    # Reflection APIs have a history of being abused, accidentally disclosing
-    # sensitive data, etc. So we have a config knob.
-    if not ui.configbool(b'experimental', b'web.api.debugreflect'):
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(_(b'debugreflect service not available'))
-        return
-
-    # We assume we have a unified framing protocol request body.
-
-    reactor = wireprotoframing.serverreactor(ui)
-    states = []
-
-    while True:
-        frame = wireprotoframing.readframe(req.bodyfh)
-
-        if not frame:
-            states.append(b'received: <no frame>')
-            break
-
-        states.append(
-            b'received: %d %d %d %s'
-            % (frame.typeid, frame.flags, frame.requestid, frame.payload)
-        )
-
-        action, meta = reactor.onframerecv(frame)
-        states.append(templatefilters.json((action, meta)))
-
-    action, meta = reactor.oninputeof()
-    meta[b'action'] = action
-    states.append(templatefilters.json(meta))
-
-    res.status = b'200 OK'
-    res.headers[b'Content-Type'] = b'text/plain'
-    res.setbodybytes(b'\n'.join(states))
-
-
-def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
-    """Post-validation handler for HTTPv2 requests.
-
-    Called when the HTTP request contains unified frame-based protocol
-    frames for evaluation.
-    """
-    # TODO Some HTTP clients are full duplex and can receive data before
-    # the entire request is transmitted. Figure out a way to indicate support
-    # for that so we can opt into full duplex mode.
-    reactor = wireprotoframing.serverreactor(ui, deferoutput=True)
-    seencommand = False
-
-    outstream = None
-
-    while True:
-        frame = wireprotoframing.readframe(req.bodyfh)
-        if not frame:
-            break
-
-        action, meta = reactor.onframerecv(frame)
-
-        if action == b'wantframe':
-            # Need more data before we can do anything.
-            continue
-        elif action == b'runcommand':
-            # Defer creating output stream because we need to wait for
-            # protocol settings frames so proper encoding can be applied.
-            if not outstream:
-                outstream = reactor.makeoutputstream()
-
-            sentoutput = _httpv2runcommand(
-                ui,
-                repo,
-                req,
-                res,
-                authedperm,
-                reqcommand,
-                reactor,
-                outstream,
-                meta,
-                issubsequent=seencommand,
-            )
-
-            if sentoutput:
-                return
-
-            seencommand = True
-
-        elif action == b'error':
-            # TODO define proper error mechanism.
-            res.status = b'200 OK'
-            res.headers[b'Content-Type'] = b'text/plain'
-            res.setbodybytes(meta[b'message'] + b'\n')
-            return
-        else:
-            raise error.ProgrammingError(
-                b'unhandled action from frame processor: %s' % action
-            )
-
-    action, meta = reactor.oninputeof()
-    if action == b'sendframes':
-        # We assume we haven't started sending the response yet. If we're
-        # wrong, the response type will raise an exception.
-        res.status = b'200 OK'
-        res.headers[b'Content-Type'] = FRAMINGTYPE
-        res.setbodygen(meta[b'framegen'])
-    elif action == b'noop':
-        pass
-    else:
-        raise error.ProgrammingError(
-            b'unhandled action from frame processor: %s' % action
-        )
-
-
-def _httpv2runcommand(
-    ui,
-    repo,
-    req,
-    res,
-    authedperm,
-    reqcommand,
-    reactor,
-    outstream,
-    command,
-    issubsequent,
-):
-    """Dispatch a wire protocol command made from HTTPv2 requests.
-
-    The authenticated permission (``authedperm``) along with the original
-    command from the URL (``reqcommand``) are passed in.
-    """
-    # We already validated that the session has permissions to perform the
-    # actions in ``authedperm``. In the unified frame protocol, the canonical
-    # command to run is expressed in a frame. However, the URL also requested
-    # to run a specific command. We need to be careful that the command we
-    # run doesn't have permissions requirements greater than what was granted
-    # by ``authedperm``.
-    #
-    # Our rule for this is we only allow one command per HTTP request and
-    # that command must match the command in the URL. However, we make
-    # an exception for the ``multirequest`` URL. This URL is allowed to
-    # execute multiple commands. We double check permissions of each command
-    # as it is invoked to ensure there is no privilege escalation.
-    # TODO consider allowing multiple commands to regular command URLs
-    # iff each command is the same.
-
-    proto = httpv2protocolhandler(req, ui, args=command[b'args'])
-
-    if reqcommand == b'multirequest':
-        if not COMMANDS.commandavailable(command[b'command'], proto):
-            # TODO proper error mechanism
-            res.status = b'200 OK'
-            res.headers[b'Content-Type'] = b'text/plain'
-            res.setbodybytes(
-                _(b'wire protocol command not available: %s')
-                % command[b'command']
-            )
-            return True
-
-        # TODO don't use assert here, since it may be elided by -O.
-        assert authedperm in (b'ro', b'rw')
-        wirecommand = COMMANDS[command[b'command']]
-        assert wirecommand.permission in (b'push', b'pull')
-
-        if authedperm == b'ro' and wirecommand.permission != b'pull':
-            # TODO proper error mechanism
-            res.status = b'403 Forbidden'
-            res.headers[b'Content-Type'] = b'text/plain'
-            res.setbodybytes(
-                _(b'insufficient permissions to execute command: %s')
-                % command[b'command']
-            )
-            return True
-
-        # TODO should we also call checkperm() here? Maybe not if we're going
-        # to overhaul that API. The granted scope from the URL check should
-        # be good enough.
-
-    else:
-        # Don't allow multiple commands outside of ``multirequest`` URL.
-        if issubsequent:
-            # TODO proper error mechanism
-            res.status = b'200 OK'
-            res.headers[b'Content-Type'] = b'text/plain'
-            res.setbodybytes(
-                _(b'multiple commands cannot be issued to this URL')
-            )
-            return True
-
-        if reqcommand != command[b'command']:
-            # TODO define proper error mechanism
-            res.status = b'200 OK'
-            res.headers[b'Content-Type'] = b'text/plain'
-            res.setbodybytes(_(b'command in frame must match command in URL'))
-            return True
-
-    res.status = b'200 OK'
-    res.headers[b'Content-Type'] = FRAMINGTYPE
-
-    try:
-        objs = dispatch(repo, proto, command[b'command'], command[b'redirect'])
-
-        action, meta = reactor.oncommandresponsereadyobjects(
-            outstream, command[b'requestid'], objs
-        )
-
-    except error.WireprotoCommandError as e:
-        action, meta = reactor.oncommanderror(
-            outstream, command[b'requestid'], e.message, e.messageargs
-        )
-
-    except Exception as e:
-        action, meta = reactor.onservererror(
-            outstream,
-            command[b'requestid'],
-            _(b'exception when invoking command: %s')
-            % stringutil.forcebytestr(e),
-        )
-
-    if action == b'sendframes':
-        res.setbodygen(meta[b'framegen'])
-        return True
-    elif action == b'noop':
-        return False
-    else:
-        raise error.ProgrammingError(
-            b'unhandled event from reactor: %s' % action
-        )
-
-
-def getdispatchrepo(repo, proto, command):
-    viewconfig = repo.ui.config(b'server', b'view')
-    return repo.filtered(viewconfig)
-
-
-def dispatch(repo, proto, command, redirect):
-    """Run a wire protocol command.
-
-    Returns an iterable of objects that will be sent to the client.
-    """
-    repo = getdispatchrepo(repo, proto, command)
-
-    entry = COMMANDS[command]
-    func = entry.func
-    spec = entry.args
-
-    args = proto.getargs(spec)
-
-    # There is some duplicate boilerplate code here for calling the command and
-    # emitting objects. It is either that or a lot of indented code that looks
-    # like a pyramid (since there are a lot of code paths that result in not
-    # using the cacher).
-    callcommand = lambda: func(repo, proto, **pycompat.strkwargs(args))
-
-    # Request is not cacheable. Don't bother instantiating a cacher.
-    if not entry.cachekeyfn:
-        for o in callcommand():
-            yield o
-        return
-
-    if redirect:
-        redirecttargets = redirect[b'targets']
-        redirecthashes = redirect[b'hashes']
-    else:
-        redirecttargets = []
-        redirecthashes = []
-
-    cacher = makeresponsecacher(
-        repo,
-        proto,
-        command,
-        args,
-        cborutil.streamencode,
-        redirecttargets=redirecttargets,
-        redirecthashes=redirecthashes,
-    )
-
-    # But we have no cacher. Do default handling.
-    if not cacher:
-        for o in callcommand():
-            yield o
-        return
-
-    with cacher:
-        cachekey = entry.cachekeyfn(
-            repo, proto, cacher, **pycompat.strkwargs(args)
-        )
-
-        # No cache key or the cacher doesn't like it. Do default handling.
-        if cachekey is None or not cacher.setcachekey(cachekey):
-            for o in callcommand():
-                yield o
-            return
-
-        # Serve it from the cache, if possible.
-        cached = cacher.lookup()
-
-        if cached:
-            for o in cached[b'objs']:
-                yield o
-            return
-
-        # Else call the command and feed its output into the cacher, allowing
-        # the cacher to buffer/mutate objects as it desires.
-        for o in callcommand():
-            for o in cacher.onobject(o):
-                yield o
-
-        for o in cacher.onfinished():
-            yield o
-
-
-@interfaceutil.implementer(wireprototypes.baseprotocolhandler)
-class httpv2protocolhandler(object):
-    def __init__(self, req, ui, args=None):
-        self._req = req
-        self._ui = ui
-        self._args = args
-
-    @property
-    def name(self):
-        return HTTP_WIREPROTO_V2
-
-    def getargs(self, args):
-        # First look for args that were passed but aren't registered on this
-        # command.
-        extra = set(self._args) - set(args)
-        if extra:
-            raise error.WireprotoCommandError(
-                b'unsupported argument to command: %s'
-                % b', '.join(sorted(extra))
-            )
-
-        # And look for required arguments that are missing.
-        missing = {a for a in args if args[a][b'required']} - set(self._args)
-
-        if missing:
-            raise error.WireprotoCommandError(
-                b'missing required arguments: %s' % b', '.join(sorted(missing))
-            )
-
-        # Now derive the arguments to pass to the command, taking into
-        # account the arguments specified by the client.
-        data = {}
-        for k, meta in sorted(args.items()):
-            # This argument wasn't passed by the client.
-            if k not in self._args:
-                data[k] = meta[b'default']()
-                continue
-
-            v = self._args[k]
-
-            # Sets may be expressed as lists. Silently normalize.
-            if meta[b'type'] == b'set' and isinstance(v, list):
-                v = set(v)
-
-            # TODO consider more/stronger type validation.
-
-            data[k] = v
-
-        return data
-
-    def getprotocaps(self):
-        # Protocol capabilities are currently not implemented for HTTP V2.
-        return set()
-
-    def getpayload(self):
-        raise NotImplementedError
-
-    @contextlib.contextmanager
-    def mayberedirectstdio(self):
-        raise NotImplementedError
-
-    def client(self):
-        raise NotImplementedError
-
-    def addcapabilities(self, repo, caps):
-        return caps
-
-    def checkperm(self, perm):
-        raise NotImplementedError
-
-
-def httpv2apidescriptor(req, repo):
-    proto = httpv2protocolhandler(req, repo.ui)
-
-    return _capabilitiesv2(repo, proto)
-
-
-def _capabilitiesv2(repo, proto):
-    """Obtain the set of capabilities for version 2 transports.
-
-    These capabilities are distinct from the capabilities for version 1
-    transports.
-    """
-    caps = {
-        b'commands': {},
-        b'framingmediatypes': [FRAMINGTYPE],
-        b'pathfilterprefixes': set(narrowspec.VALID_PREFIXES),
-    }
-
-    for command, entry in COMMANDS.items():
-        args = {}
-
-        for arg, meta in entry.args.items():
-            args[arg] = {
-                # TODO should this be a normalized type using CBOR's
-                # terminology?
-                b'type': meta[b'type'],
-                b'required': meta[b'required'],
-            }
-
-            if not meta[b'required']:
-                args[arg][b'default'] = meta[b'default']()
-
-            if meta[b'validvalues']:
-                args[arg][b'validvalues'] = meta[b'validvalues']
-
-        # TODO this type of check should be defined in a per-command callback.
-        if (
-            command == b'rawstorefiledata'
-            and not streamclone.allowservergeneration(repo)
-        ):
-            continue
-
-        # pytype: disable=unsupported-operands
-        caps[b'commands'][command] = {
-            b'args': args,
-            b'permissions': [entry.permission],
-        }
-        # pytype: enable=unsupported-operands
-
-        if entry.extracapabilitiesfn:
-            extracaps = entry.extracapabilitiesfn(repo, proto)
-            caps[b'commands'][command].update(extracaps)
-
-    caps[b'rawrepoformats'] = sorted(repo.requirements & repo.supportedformats)
-
-    targets = getadvertisedredirecttargets(repo, proto)
-    if targets:
-        caps[b'redirect'] = {
-            b'targets': [],
-            b'hashes': [b'sha256', b'sha1'],
-        }
-
-        for target in targets:
-            entry = {
-                b'name': target[b'name'],
-                b'protocol': target[b'protocol'],
-                b'uris': target[b'uris'],
-            }
-
-            for key in (b'snirequired', b'tlsversions'):
-                if key in target:
-                    entry[key] = target[key]
-
-            # pytype: disable=attribute-error
-            caps[b'redirect'][b'targets'].append(entry)
-            # pytype: enable=attribute-error
-
-    return proto.addcapabilities(repo, caps)
-
-
-def getadvertisedredirecttargets(repo, proto):
-    """Obtain a list of content redirect targets.
-
-    Returns a list containing potential redirect targets that will be
-    advertised in capabilities data. Each dict MUST have the following
-    keys:
-
-    name
-       The name of this redirect target. This is the identifier clients use
-       to refer to a target. It is transferred as part of every command
-       request.
-
-    protocol
-       Network protocol used by this target. Typically this is the string
-       in front of the ``://`` in a URL. e.g. ``https``.
-
-    uris
-       List of representative URIs for this target. Clients can use the
-       URIs to test parsing for compatibility or for ordering preference
-       for which target to use.
-
-    The following optional keys are recognized:
-
-    snirequired
-       Bool indicating if Server Name Indication (SNI) is required to
-       connect to this target.
-
-    tlsversions
-       List of bytes indicating which TLS versions are supported by this
-       target.
-
-    By default, clients reflect the target order advertised by servers
-    and servers will use the first client-advertised target when picking
-    a redirect target. So targets should be advertised in the order the
-    server prefers they be used.
-    """
-    return []
-
-
-def wireprotocommand(
-    name,
-    args=None,
-    permission=b'push',
-    cachekeyfn=None,
-    extracapabilitiesfn=None,
-):
-    """Decorator to declare a wire protocol command.
-
-    ``name`` is the name of the wire protocol command being provided.
-
-    ``args`` is a dict defining arguments accepted by the command. Keys are
-    the argument name. Values are dicts with the following keys:
-
-       ``type``
-          The argument data type. Must be one of the following string
-          literals: ``bytes``, ``int``, ``list``, ``dict``, ``set``,
-          or ``bool``.
-
-       ``default``
-          A callable returning the default value for this argument. If not
-          specified, ``None`` will be the default value.
-
-       ``example``
-          An example value for this argument.
-
-       ``validvalues``
-          Set of recognized values for this argument.
-
-    ``permission`` defines the permission type needed to run this command.
-    Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
-    respectively. Default is to assume command requires ``push`` permissions
-    because otherwise commands not declaring their permissions could modify
-    a repository that is supposed to be read-only.
-
-    ``cachekeyfn`` defines an optional callable that can derive the
-    cache key for this request.
-
-    ``extracapabilitiesfn`` defines an optional callable that defines extra
-    command capabilities/parameters that are advertised next to the command
-    in the capabilities data structure describing the server. The callable
-    receives as arguments the repository and protocol objects. It returns
-    a dict of extra fields to add to the command descriptor.
-
-    Wire protocol commands are generators of objects to be serialized and
-    sent to the client.
-
-    If a command raises an uncaught exception, this will be translated into
-    a command error.
-
-    All commands can opt in to being cacheable by defining a function
-    (``cachekeyfn``) that is called to derive a cache key. This function
-    receives the same arguments as the command itself plus a ``cacher``
-    argument containing the active cacher for the request and returns a bytes
-    containing the key in a cache the response to this command may be cached
-    under.
-    """
-    transports = {
-        k for k, v in wireprototypes.TRANSPORTS.items() if v[b'version'] == 2
-    }
-
-    if permission not in (b'push', b'pull'):
-        raise error.ProgrammingError(
-            b'invalid wire protocol permission; '
-            b'got %s; expected "push" or "pull"' % permission
-        )
-
-    if args is None:
-        args = {}
-
-    if not isinstance(args, dict):
-        raise error.ProgrammingError(
-            b'arguments for version 2 commands must be declared as dicts'
-        )
-
-    for arg, meta in args.items():
-        if arg == b'*':
-            raise error.ProgrammingError(
-                b'* argument name not allowed on version 2 commands'
-            )
-
-        if not isinstance(meta, dict):
-            raise error.ProgrammingError(
-                b'arguments for version 2 commands '
-                b'must declare metadata as a dict'
-            )
-
-        if b'type' not in meta:
-            raise error.ProgrammingError(
-                b'%s argument for command %s does not '
-                b'declare type field' % (arg, name)
-            )
-
-        if meta[b'type'] not in (
-            b'bytes',
-            b'int',
-            b'list',
-            b'dict',
-            b'set',
-            b'bool',
-        ):
-            raise error.ProgrammingError(
-                b'%s argument for command %s has '
-                b'illegal type: %s' % (arg, name, meta[b'type'])
-            )
-
-        if b'example' not in meta:
-            raise error.ProgrammingError(
-                b'%s argument for command %s does not '
-                b'declare example field' % (arg, name)
-            )
-
-        meta[b'required'] = b'default' not in meta
-
-        meta.setdefault(b'default', lambda: None)
-        meta.setdefault(b'validvalues', None)
-
-    def register(func):
-        if name in COMMANDS:
-            raise error.ProgrammingError(
-                b'%s command already registered for version 2' % name
-            )
-
-        COMMANDS[name] = wireprototypes.commandentry(
-            func,
-            args=args,
-            transports=transports,
-            permission=permission,
-            cachekeyfn=cachekeyfn,
-            extracapabilitiesfn=extracapabilitiesfn,
-        )
-
-        return func
-
-    return register
-
-
-def makecommandcachekeyfn(command, localversion=None, allargs=False):
-    """Construct a cache key derivation function with common features.
-
-    By default, the cache key is a hash of:
-
-    * The command name.
-    * A global cache version number.
-    * A local cache version number (passed via ``localversion``).
-    * All the arguments passed to the command.
-    * The media type used.
-    * Wire protocol version string.
-    * The repository path.
-    """
-    if not allargs:
-        raise error.ProgrammingError(
-            b'only allargs=True is currently supported'
-        )
-
-    if localversion is None:
-        raise error.ProgrammingError(b'must set localversion argument value')
-
-    def cachekeyfn(repo, proto, cacher, **args):
-        spec = COMMANDS[command]
-
-        # Commands that mutate the repo can not be cached.
-        if spec.permission == b'push':
-            return None
-
-        # TODO config option to disable caching.
-
-        # Our key derivation strategy is to construct a data structure
-        # holding everything that could influence cacheability and to hash
-        # the CBOR representation of that. Using CBOR seems like it might
-        # be overkill. However, simpler hashing mechanisms are prone to
-        # duplicate input issues. e.g. if you just concatenate two values,
-        # "foo"+"bar" is identical to "fo"+"obar". Using CBOR provides
-        # "padding" between values and prevents these problems.
-
-        # Seed the hash with various data.
-        state = {
-            # To invalidate all cache keys.
-            b'globalversion': GLOBAL_CACHE_VERSION,
-            # More granular cache key invalidation.
-            b'localversion': localversion,
-            # Cache keys are segmented by command.
-            b'command': command,
-            # Throw in the media type and API version strings so changes
-            # to exchange semantics invalid cache.
-            b'mediatype': FRAMINGTYPE,
-            b'version': HTTP_WIREPROTO_V2,
-            # So same requests for different repos don't share cache keys.
-            b'repo': repo.root,
-        }
-
-        # The arguments passed to us will have already been normalized.
-        # Default values will be set, etc. This is important because it
-        # means that it doesn't matter if clients send an explicit argument
-        # or rely on the default value: it will all normalize to the same
-        # set of arguments on the server and therefore the same cache key.
-        #
-        # Arguments by their very nature must support being encoded to CBOR.
-        # And the CBOR encoder is deterministic. So we hash the arguments
-        # by feeding the CBOR of their representation into the hasher.
-        if allargs:
-            state[b'args'] = pycompat.byteskwargs(args)
-
-        cacher.adjustcachekeystate(state)
-
-        hasher = hashutil.sha1()
-        for chunk in cborutil.streamencode(state):
-            hasher.update(chunk)
-
-        return pycompat.sysbytes(hasher.hexdigest())
-
-    return cachekeyfn
-
-
-def makeresponsecacher(
-    repo, proto, command, args, objencoderfn, redirecttargets, redirecthashes
-):
-    """Construct a cacher for a cacheable command.
-
-    Returns an ``iwireprotocolcommandcacher`` instance.
-
-    Extensions can monkeypatch this function to provide custom caching
-    backends.
-    """
-    return None
-
-
-def resolvenodes(repo, revisions):
-    """Resolve nodes from a revisions specifier data structure."""
-    cl = repo.changelog
-    clhasnode = cl.hasnode
-
-    seen = set()
-    nodes = []
-
-    if not isinstance(revisions, list):
-        raise error.WireprotoCommandError(
-            b'revisions must be defined as an array'
-        )
-
-    for spec in revisions:
-        if b'type' not in spec:
-            raise error.WireprotoCommandError(
-                b'type key not present in revision specifier'
-            )
-
-        typ = spec[b'type']
-
-        if typ == b'changesetexplicit':
-            if b'nodes' not in spec:
-                raise error.WireprotoCommandError(
-                    b'nodes key not present in changesetexplicit revision '
-                    b'specifier'
-                )
-
-            for node in spec[b'nodes']:
-                if node not in seen:
-                    nodes.append(node)
-                    seen.add(node)
-
-        elif typ == b'changesetexplicitdepth':
-            for key in (b'nodes', b'depth'):
-                if key not in spec:
-                    raise error.WireprotoCommandError(
-                        b'%s key not present in changesetexplicitdepth revision '
-                        b'specifier',
-                        (key,),
-                    )
-
-            for rev in repo.revs(
-                b'ancestors(%ln, %s)', spec[b'nodes'], spec[b'depth'] - 1
-            ):
-                node = cl.node(rev)
-
-                if node not in seen:
-                    nodes.append(node)
-                    seen.add(node)
-
-        elif typ == b'changesetdagrange':
-            for key in (b'roots', b'heads'):
-                if key not in spec:
-                    raise error.WireprotoCommandError(
-                        b'%s key not present in changesetdagrange revision '
-                        b'specifier',
-                        (key,),
-                    )
-
-            if not spec[b'heads']:
-                raise error.WireprotoCommandError(
-                    b'heads key in changesetdagrange cannot be empty'
-                )
-
-            if spec[b'roots']:
-                common = [n for n in spec[b'roots'] if clhasnode(n)]
-            else:
-                common = [repo.nullid]
-
-            for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
-                if n not in seen:
-                    nodes.append(n)
-                    seen.add(n)
-
-        else:
-            raise error.WireprotoCommandError(
-                b'unknown revision specifier type: %s', (typ,)
-            )
-
-    return nodes
-
-
-@wireprotocommand(b'branchmap', permission=b'pull')
-def branchmapv2(repo, proto):
-    yield {
-        encoding.fromlocal(k): v
-        for k, v in pycompat.iteritems(repo.branchmap())
-    }
-
-
-@wireprotocommand(b'capabilities', permission=b'pull')
-def capabilitiesv2(repo, proto):
-    yield _capabilitiesv2(repo, proto)
-
-
-@wireprotocommand(
-    b'changesetdata',
-    args={
-        b'revisions': {
-            b'type': b'list',
-            b'example': [
-                {
-                    b'type': b'changesetexplicit',
-                    b'nodes': [b'abcdef...'],
-                }
-            ],
-        },
-        b'fields': {
-            b'type': b'set',
-            b'default': set,
-            b'example': {b'parents', b'revision'},
-            b'validvalues': {b'bookmarks', b'parents', b'phase', b'revision'},
-        },
-    },
-    permission=b'pull',
-)
-def changesetdata(repo, proto, revisions, fields):
-    # TODO look for unknown fields and abort when they can't be serviced.
-    # This could probably be validated by dispatcher using validvalues.
-
-    cl = repo.changelog
-    outgoing = resolvenodes(repo, revisions)
-    publishing = repo.publishing()
-
-    if outgoing:
-        repo.hook(b'preoutgoing', throw=True, source=b'serve')
-
-    yield {
-        b'totalitems': len(outgoing),
-    }
-
-    # The phases of nodes already transferred to the client may have changed
-    # since the client last requested data. We send phase-only records
-    # for these revisions, if requested.
-    # TODO actually do this. We'll probably want to emit phase heads
-    # in the ancestry set of the outgoing revisions. This will ensure
-    # that phase updates within that set are seen.
-    if b'phase' in fields:
-        pass
-
-    nodebookmarks = {}
-    for mark, node in repo._bookmarks.items():
-        nodebookmarks.setdefault(node, set()).add(mark)
-
-    # It is already topologically sorted by revision number.
-    for node in outgoing:
-        d = {
-            b'node': node,
-        }
-
-        if b'parents' in fields:
-            d[b'parents'] = cl.parents(node)
-
-        if b'phase' in fields:
-            if publishing:
-                d[b'phase'] = b'public'
-            else:
-                ctx = repo[node]
-                d[b'phase'] = ctx.phasestr()
-
-        if b'bookmarks' in fields and node in nodebookmarks:
-            d[b'bookmarks'] = sorted(nodebookmarks[node])
-            del nodebookmarks[node]
-
-        followingmeta = []
-        followingdata = []
-
-        if b'revision' in fields:
-            revisiondata = cl.revision(node)
-            followingmeta.append((b'revision', len(revisiondata)))
-            followingdata.append(revisiondata)
-
-        # TODO make it possible for extensions to wrap a function or register
-        # a handler to service custom fields.
-
-        if followingmeta:
-            d[b'fieldsfollowing'] = followingmeta
-
-        yield d
-
-        for extra in followingdata:
-            yield extra
-
-    # If requested, send bookmarks from nodes that didn't have revision
-    # data sent so receiver is aware of any bookmark updates.
-    if b'bookmarks' in fields:
-        for node, marks in sorted(pycompat.iteritems(nodebookmarks)):
-            yield {
-                b'node': node,
-                b'bookmarks': sorted(marks),
-            }
-
-
-class FileAccessError(Exception):
-    """Represents an error accessing a specific file."""
-
-    def __init__(self, path, msg, args):
-        self.path = path
-        self.msg = msg
-        self.args = args
-
-
-def getfilestore(repo, proto, path):
-    """Obtain a file storage object for use with wire protocol.
-
-    Exists as a standalone function so extensions can monkeypatch to add
-    access control.
-    """
-    # This seems to work even if the file doesn't exist. So catch
-    # "empty" files and return an error.
-    fl = repo.file(path)
-
-    if not len(fl):
-        raise FileAccessError(path, b'unknown file: %s', (path,))
-
-    return fl
-
-
-def emitfilerevisions(repo, path, revisions, linknodes, fields):
-    for revision in revisions:
-        d = {
-            b'node': revision.node,
-        }
-
-        if b'parents' in fields:
-            d[b'parents'] = [revision.p1node, revision.p2node]
-
-        if b'linknode' in fields:
-            d[b'linknode'] = linknodes[revision.node]
-
-        followingmeta = []
-        followingdata = []
-
-        if b'revision' in fields:
-            if revision.revision is not None:
-                followingmeta.append((b'revision', len(revision.revision)))
-                followingdata.append(revision.revision)
-            else:
-                d[b'deltabasenode'] = revision.basenode
-                followingmeta.append((b'delta', len(revision.delta)))
-                followingdata.append(revision.delta)
-
-        if followingmeta:
-            d[b'fieldsfollowing'] = followingmeta
-
-        yield d
-
-        for extra in followingdata:
-            yield extra
-
-
-def makefilematcher(repo, pathfilter):
-    """Construct a matcher from a path filter dict."""
-
-    # Validate values.
-    if pathfilter:
-        for key in (b'include', b'exclude'):
-            for pattern in pathfilter.get(key, []):
-                if not pattern.startswith((b'path:', b'rootfilesin:')):
-                    raise error.WireprotoCommandError(
-                        b'%s pattern must begin with `path:` or `rootfilesin:`; '
-                        b'got %s',
-                        (key, pattern),
-                    )
-
-    if pathfilter:
-        matcher = matchmod.match(
-            repo.root,
-            b'',
-            include=pathfilter.get(b'include', []),
-            exclude=pathfilter.get(b'exclude', []),
-        )
-    else:
-        matcher = matchmod.match(repo.root, b'')
-
-    # Requested patterns could include files not in the local store. So
-    # filter those out.
-    return repo.narrowmatch(matcher)
-
-
-@wireprotocommand(
-    b'filedata',
-    args={
-        b'haveparents': {
-            b'type': b'bool',
-            b'default': lambda: False,
-            b'example': True,
-        },
-        b'nodes': {
-            b'type': b'list',
-            b'example': [b'0123456...'],
-        },
-        b'fields': {
-            b'type': b'set',
-            b'default': set,
-            b'example': {b'parents', b'revision'},
-            b'validvalues': {b'parents', b'revision', b'linknode'},
-        },
-        b'path': {
-            b'type': b'bytes',
-            b'example': b'foo.txt',
-        },
-    },
-    permission=b'pull',
-    # TODO censoring a file revision won't invalidate the cache.
-    # Figure out a way to take censoring into account when deriving
-    # the cache key.
-    cachekeyfn=makecommandcachekeyfn(b'filedata', 1, allargs=True),
-)
-def filedata(repo, proto, haveparents, nodes, fields, path):
-    # TODO this API allows access to file revisions that are attached to
-    # secret changesets. filesdata does not have this problem. Maybe this
-    # API should be deleted?
-
-    try:
-        # Extensions may wish to access the protocol handler.
-        store = getfilestore(repo, proto, path)
-    except FileAccessError as e:
-        raise error.WireprotoCommandError(e.msg, e.args)
-
-    clnode = repo.changelog.node
-    linknodes = {}
-
-    # Validate requested nodes.
-    for node in nodes:
-        try:
-            store.rev(node)
-        except error.LookupError:
-            raise error.WireprotoCommandError(
-                b'unknown file node: %s', (hex(node),)
-            )
-
-        # TODO by creating the filectx against a specific file revision
-        # instead of changeset, linkrev() is always used. This is wrong for
-        # cases where linkrev() may refer to a hidden changeset. But since this
-        # API doesn't know anything about changesets, we're not sure how to
-        # disambiguate the linknode. Perhaps we should delete this API?
-        fctx = repo.filectx(path, fileid=node)
-        linknodes[node] = clnode(fctx.introrev())
-
-    revisions = store.emitrevisions(
-        nodes,
-        revisiondata=b'revision' in fields,
-        assumehaveparentrevisions=haveparents,
-    )
-
-    yield {
-        b'totalitems': len(nodes),
-    }
-
-    for o in emitfilerevisions(repo, path, revisions, linknodes, fields):
-        yield o
-
-
-def filesdatacapabilities(repo, proto):
-    batchsize = repo.ui.configint(
-        b'experimental', b'server.filesdata.recommended-batch-size'
-    )
-    return {
-        b'recommendedbatchsize': batchsize,
-    }
-
-
-@wireprotocommand(
-    b'filesdata',
-    args={
-        b'haveparents': {
-            b'type': b'bool',
-            b'default': lambda: False,
-            b'example': True,
-        },
-        b'fields': {
-            b'type': b'set',
-            b'default': set,
-            b'example': {b'parents', b'revision'},
-            b'validvalues': {
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision',
-            },
-        },
-        b'pathfilter': {
-            b'type': b'dict',
-            b'default': lambda: None,
-            b'example': {b'include': [b'path:tests']},
-        },
-        b'revisions': {
-            b'type': b'list',
-            b'example': [
-                {
-                    b'type': b'changesetexplicit',
-                    b'nodes': [b'abcdef...'],
-                }
-            ],
-        },
-    },
-    permission=b'pull',
-    # TODO censoring a file revision won't invalidate the cache.
-    # Figure out a way to take censoring into account when deriving
-    # the cache key.
-    cachekeyfn=makecommandcachekeyfn(b'filesdata', 1, allargs=True),
-    extracapabilitiesfn=filesdatacapabilities,
-)
-def filesdata(repo, proto, haveparents, fields, pathfilter, revisions):
-    # TODO This should operate on a repo that exposes obsolete changesets. There
-    # is a race between a client making a push that obsoletes a changeset and
-    # another client fetching files data for that changeset. If a client has a
-    # changeset, it should probably be allowed to access files data for that
-    # changeset.
-
-    outgoing = resolvenodes(repo, revisions)
-    filematcher = makefilematcher(repo, pathfilter)
-
-    # path -> {fnode: linknode}
-    fnodes = collections.defaultdict(dict)
-
-    # We collect the set of relevant file revisions by iterating the changeset
-    # revisions and either walking the set of files recorded in the changeset
-    # or by walking the manifest at that revision. There is probably room for a
-    # storage-level API to request this data, as it can be expensive to compute
-    # and would benefit from caching or alternate storage from what revlogs
-    # provide.
-    for node in outgoing:
-        ctx = repo[node]
-        mctx = ctx.manifestctx()
-        md = mctx.read()
-
-        if haveparents:
-            checkpaths = ctx.files()
-        else:
-            checkpaths = md.keys()
-
-        for path in checkpaths:
-            fnode = md[path]
-
-            if path in fnodes and fnode in fnodes[path]:
-                continue
-
-            if not filematcher(path):
-                continue
-
-            fnodes[path].setdefault(fnode, node)
-
-    yield {
-        b'totalpaths': len(fnodes),
-        b'totalitems': sum(len(v) for v in fnodes.values()),
-    }
-
-    for path, filenodes in sorted(fnodes.items()):
-        try:
-            store = getfilestore(repo, proto, path)
-        except FileAccessError as e:
-            raise error.WireprotoCommandError(e.msg, e.args)
-
-        yield {
-            b'path': path,
-            b'totalitems': len(filenodes),
-        }
-
-        revisions = store.emitrevisions(
-            filenodes.keys(),
-            revisiondata=b'revision' in fields,
-            assumehaveparentrevisions=haveparents,
-        )
-
-        for o in emitfilerevisions(repo, path, revisions, filenodes, fields):
-            yield o
-
-
-@wireprotocommand(
-    b'heads',
-    args={
-        b'publiconly': {
-            b'type': b'bool',
-            b'default': lambda: False,
-            b'example': False,
-        },
-    },
-    permission=b'pull',
-)
-def headsv2(repo, proto, publiconly):
-    if publiconly:
-        repo = repo.filtered(b'immutable')
-
-    yield repo.heads()
-
-
-@wireprotocommand(
-    b'known',
-    args={
-        b'nodes': {
-            b'type': b'list',
-            b'default': list,
-            b'example': [b'deadbeef'],
-        },
-    },
-    permission=b'pull',
-)
-def knownv2(repo, proto, nodes):
-    result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
-    yield result
-
-
-@wireprotocommand(
-    b'listkeys',
-    args={
-        b'namespace': {
-            b'type': b'bytes',
-            b'example': b'ns',
-        },
-    },
-    permission=b'pull',
-)
-def listkeysv2(repo, proto, namespace):
-    keys = repo.listkeys(encoding.tolocal(namespace))
-    keys = {
-        encoding.fromlocal(k): encoding.fromlocal(v)
-        for k, v in pycompat.iteritems(keys)
-    }
-
-    yield keys
-
-
-@wireprotocommand(
-    b'lookup',
-    args={
-        b'key': {
-            b'type': b'bytes',
-            b'example': b'foo',
-        },
-    },
-    permission=b'pull',
-)
-def lookupv2(repo, proto, key):
-    key = encoding.tolocal(key)
-
-    # TODO handle exception.
-    node = repo.lookup(key)
-
-    yield node
-
-
-def manifestdatacapabilities(repo, proto):
-    batchsize = repo.ui.configint(
-        b'experimental', b'server.manifestdata.recommended-batch-size'
-    )
-
-    return {
-        b'recommendedbatchsize': batchsize,
-    }
-
-
-@wireprotocommand(
-    b'manifestdata',
-    args={
-        b'nodes': {
-            b'type': b'list',
-            b'example': [b'0123456...'],
-        },
-        b'haveparents': {
-            b'type': b'bool',
-            b'default': lambda: False,
-            b'example': True,
-        },
-        b'fields': {
-            b'type': b'set',
-            b'default': set,
-            b'example': {b'parents', b'revision'},
-            b'validvalues': {b'parents', b'revision'},
-        },
-        b'tree': {
-            b'type': b'bytes',
-            b'example': b'',
-        },
-    },
-    permission=b'pull',
-    cachekeyfn=makecommandcachekeyfn(b'manifestdata', 1, allargs=True),
-    extracapabilitiesfn=manifestdatacapabilities,
-)
-def manifestdata(repo, proto, haveparents, nodes, fields, tree):
-    store = repo.manifestlog.getstorage(tree)
-
-    # Validate the node is known and abort on unknown revisions.
-    for node in nodes:
-        try:
-            store.rev(node)
-        except error.LookupError:
-            raise error.WireprotoCommandError(b'unknown node: %s', (node,))
-
-    revisions = store.emitrevisions(
-        nodes,
-        revisiondata=b'revision' in fields,
-        assumehaveparentrevisions=haveparents,
-    )
-
-    yield {
-        b'totalitems': len(nodes),
-    }
-
-    for revision in revisions:
-        d = {
-            b'node': revision.node,
-        }
-
-        if b'parents' in fields:
-            d[b'parents'] = [revision.p1node, revision.p2node]
-
-        followingmeta = []
-        followingdata = []
-
-        if b'revision' in fields:
-            if revision.revision is not None:
-                followingmeta.append((b'revision', len(revision.revision)))
-                followingdata.append(revision.revision)
-            else:
-                d[b'deltabasenode'] = revision.basenode
-                followingmeta.append((b'delta', len(revision.delta)))
-                followingdata.append(revision.delta)
-
-        if followingmeta:
-            d[b'fieldsfollowing'] = followingmeta
-
-        yield d
-
-        for extra in followingdata:
-            yield extra
-
-
-@wireprotocommand(
-    b'pushkey',
-    args={
-        b'namespace': {
-            b'type': b'bytes',
-            b'example': b'ns',
-        },
-        b'key': {
-            b'type': b'bytes',
-            b'example': b'key',
-        },
-        b'old': {
-            b'type': b'bytes',
-            b'example': b'old',
-        },
-        b'new': {
-            b'type': b'bytes',
-            b'example': b'new',
-        },
-    },
-    permission=b'push',
-)
-def pushkeyv2(repo, proto, namespace, key, old, new):
-    # TODO handle ui output redirection
-    yield repo.pushkey(
-        encoding.tolocal(namespace),
-        encoding.tolocal(key),
-        encoding.tolocal(old),
-        encoding.tolocal(new),
-    )
-
-
-@wireprotocommand(
-    b'rawstorefiledata',
-    args={
-        b'files': {
-            b'type': b'list',
-            b'example': [b'changelog', b'manifestlog'],
-        },
-        b'pathfilter': {
-            b'type': b'list',
-            b'default': lambda: None,
-            b'example': {b'include': [b'path:tests']},
-        },
-    },
-    permission=b'pull',
-)
-def rawstorefiledata(repo, proto, files, pathfilter):
-    if not streamclone.allowservergeneration(repo):
-        raise error.WireprotoCommandError(b'stream clone is disabled')
-
-    # TODO support dynamically advertising what store files "sets" are
-    # available. For now, we support changelog, manifestlog, and files.
-    files = set(files)
-    allowedfiles = {b'changelog', b'manifestlog'}
-
-    unsupported = files - allowedfiles
-    if unsupported:
-        raise error.WireprotoCommandError(
-            b'unknown file type: %s', (b', '.join(sorted(unsupported)),)
-        )
-
-    with repo.lock():
-        topfiles = list(repo.store.topfiles())
-
-    sendfiles = []
-    totalsize = 0
-
-    # TODO this is a bunch of storage layer interface abstractions because
-    # it assumes revlogs.
-    for rl_type, name, size in topfiles:
-        # XXX use the `rl_type` for that
-        if b'changelog' in files and name.startswith(b'00changelog'):
-            pass
-        elif b'manifestlog' in files and name.startswith(b'00manifest'):
-            pass
-        else:
-            continue
-
-        sendfiles.append((b'store', name, size))
-        totalsize += size
-
-    yield {
-        b'filecount': len(sendfiles),
-        b'totalsize': totalsize,
-    }
-
-    for location, name, size in sendfiles:
-        yield {
-            b'location': location,
-            b'path': name,
-            b'size': size,
-        }
-
-        # We have to use a closure for this to ensure the context manager is
-        # closed only after sending the final chunk.
-        def getfiledata():
-            with repo.svfs(name, b'rb', auditpath=False) as fh:
-                for chunk in util.filechunkiter(fh, limit=size):
-                    yield chunk
-
-        yield wireprototypes.indefinitebytestringresponse(getfiledata())
--- a/tests/test-bookmarks-pushpull.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-bookmarks-pushpull.t	Tue Dec 07 16:44:22 2021 +0100
@@ -715,14 +715,15 @@
   $ cat <<EOF > ../lookuphook.py
   > """small extensions adding a hook after wireprotocol lookup to test race"""
   > import functools
-  > from mercurial import wireprotov1server, wireprotov2server
+  > from mercurial import wireprotov1server
   > 
   > def wrappedlookup(orig, repo, *args, **kwargs):
   >     ret = orig(repo, *args, **kwargs)
   >     repo.hook(b'lookup')
   >     return ret
-  > for table in [wireprotov1server.commands, wireprotov2server.COMMANDS]:
-  >   table[b'lookup'].func = functools.partial(wrappedlookup, table[b'lookup'].func)
+  > 
+  > table = wireprotov1server.commands
+  > table[b'lookup'].func = functools.partial(wrappedlookup, table[b'lookup'].func)
   > EOF
   $ cat <<EOF > ../pull-race/.hg/hgrc
   > [extensions]
--- a/tests/test-bundle2-exchange.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-bundle2-exchange.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,13 +1,3 @@
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
 Test exchange of common information using bundle2
 
 
--- a/tests/test-bundle2-pushback.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-bundle2-pushback.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,13 +1,3 @@
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
   $ cat > bundle2.py << EOF
   > """A small extension to test bundle2 pushback parts.
   > Current bundle2 implementation doesn't provide a way to generate those
--- a/tests/test-bundle2-remote-changegroup.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-bundle2-remote-changegroup.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,13 +1,3 @@
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
 Create an extension to test bundle2 remote-changegroup parts
 
   $ cat > bundle2.py << EOF
--- a/tests/test-check-interfaces.py	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-check-interfaces.py	Tue Dec 07 16:44:22 2021 +0100
@@ -39,7 +39,6 @@
     wireprotoserver,
     wireprototypes,
     wireprotov1peer,
-    wireprotov2server,
 )
 
 testdir = os.path.dirname(__file__)
@@ -129,9 +128,6 @@
     ziverify.verifyClass(repository.ipeerbase, httppeer.httppeer)
     checkzobject(httppeer.httppeer(None, None, None, dummyopener(), None, None))
 
-    ziverify.verifyClass(repository.ipeerv2, httppeer.httpv2peer)
-    checkzobject(httppeer.httpv2peer(None, b'', b'', None, None, None))
-
     ziverify.verifyClass(repository.ipeerbase, localrepo.localpeer)
     checkzobject(localrepo.localpeer(dummyrepo()))
 
@@ -158,19 +154,6 @@
         )
     )
 
-    ziverify.verifyClass(repository.ipeerbase, sshpeer.sshv2peer)
-    checkzobject(
-        sshpeer.sshv2peer(
-            ui,
-            b'ssh://localhost/foo',
-            b'',
-            dummypipe(),
-            dummypipe(),
-            None,
-            None,
-        )
-    )
-
     ziverify.verifyClass(repository.ipeerbase, bundlerepo.bundlepeer)
     checkzobject(bundlerepo.bundlepeer(dummyrepo()))
 
@@ -193,26 +176,15 @@
         wireprototypes.baseprotocolhandler, wireprotoserver.sshv1protocolhandler
     )
     ziverify.verifyClass(
-        wireprototypes.baseprotocolhandler, wireprotoserver.sshv2protocolhandler
-    )
-    ziverify.verifyClass(
         wireprototypes.baseprotocolhandler,
         wireprotoserver.httpv1protocolhandler,
     )
-    ziverify.verifyClass(
-        wireprototypes.baseprotocolhandler,
-        wireprotov2server.httpv2protocolhandler,
-    )
 
     sshv1 = wireprotoserver.sshv1protocolhandler(None, None, None)
     checkzobject(sshv1)
-    sshv2 = wireprotoserver.sshv2protocolhandler(None, None, None)
-    checkzobject(sshv2)
 
     httpv1 = wireprotoserver.httpv1protocolhandler(None, None, None)
     checkzobject(httpv1)
-    httpv2 = wireprotov2server.httpv2protocolhandler(None, None)
-    checkzobject(httpv2)
 
     ziverify.verifyClass(repository.ifilestorage, filelog.filelog)
     ziverify.verifyClass(repository.imanifestdict, manifest.manifestdict)
--- a/tests/test-clone.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-clone.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,13 +1,3 @@
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
 Prepare repo a:
 
   $ hg init a
@@ -1206,14 +1196,12 @@
 #if windows
   $ hg clone "ssh://%26touch%20owned%20/" --debug
   running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio"
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg
   [255]
   $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug
   running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio"
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg
@@ -1221,14 +1209,12 @@
 #else
   $ hg clone "ssh://%3btouch%20owned%20/" --debug
   running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio'
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg
   [255]
   $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug
   running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio'
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg
@@ -1237,7 +1223,6 @@
 
   $ hg clone "ssh://v-alid.example.com/" --debug
   running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg
--- a/tests/test-http-api-httpv2.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,743 +0,0 @@
-#require no-chg
-
-  $ . $TESTDIR/wireprotohelpers.sh
-  $ enabledummycommands
-
-  $ hg init server
-  $ cat > server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > EOF
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid
-  $ cat hg.pid > $DAEMON_PIDS
-
-HTTP v2 protocol not enabled by default
-
-  $ sendhttpraw << EOF
-  > httprequest GET api/$HTTPV2
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/exp-http-v2-0003 HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 33\r\n
-  s>     \r\n
-  s>     API exp-http-v2-0003 not enabled\n
-
-Restart server with support for HTTP v2 API
-
-  $ killdaemons.py
-  $ enablehttpv2 server
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid
-  $ cat hg.pid > $DAEMON_PIDS
-
-Request to unknown command yields 404
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/badcommand
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/badcommand HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 42\r\n
-  s>     \r\n
-  s>     unknown wire protocol command: badcommand\n
-
-GET to read-only command yields a 405
-
-  $ sendhttpraw << EOF
-  > httprequest GET api/$HTTPV2/ro/customreadonly
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 405 Method Not Allowed\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Allow: POST\r\n
-  s>     Content-Length: 30\r\n
-  s>     \r\n
-  s>     commands require POST requests
-
-Missing Accept header results in 406
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/customreadonly
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 406 Not Acceptable\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 85\r\n
-  s>     \r\n
-  s>     client MUST specify Accept header with value: application/mercurial-exp-framing-0006\n
-
-Bad Accept header results in 406
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/customreadonly
-  >     accept: invalid
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: invalid\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 406 Not Acceptable\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 85\r\n
-  s>     \r\n
-  s>     client MUST specify Accept header with value: application/mercurial-exp-framing-0006\n
-
-Bad Content-Type header results in 415
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/customreadonly
-  >     accept: $MEDIATYPE
-  >     user-agent: test
-  >     content-type: badmedia
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: badmedia\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 415 Unsupported Media Type\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 88\r\n
-  s>     \r\n
-  s>     client MUST send Content-Type header with value: application/mercurial-exp-framing-0006\n
-
-Request to read-only command works out of the box
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/customreadonly
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     user-agent: test
-  >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     *\r\n (glob)
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     content-length: 29\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     27\r\n
-  s>     \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-
-  $ sendhttpv2peerverbose << EOF
-  > command customreadonly
-  > EOF
-  creating http peer for wire protocol version 2
-  sending customreadonly command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 65\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x15\x00\x00\x01\x00\x01\x00\x11\xa1DnameNcustomreadonly
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     27\r\n
-  s>     \x1f\x00\x00\x01\x00\x02\x041
-  s>     X\x1dcustomreadonly bytes response
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: gen[
-    b'customreadonly bytes response'
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-Request to read-write command fails because server is read-only by default
-
-GET to read-write request yields 405
-
-  $ sendhttpraw << EOF
-  > httprequest GET api/$HTTPV2/rw/customreadonly
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 405 Method Not Allowed\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Allow: POST\r\n
-  s>     Content-Length: 30\r\n
-  s>     \r\n
-  s>     commands require POST requests
-
-Even for unknown commands
-
-  $ sendhttpraw << EOF
-  > httprequest GET api/$HTTPV2/rw/badcommand
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/exp-http-v2-0003/rw/badcommand HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 405 Method Not Allowed\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Allow: POST\r\n
-  s>     Content-Length: 30\r\n
-  s>     \r\n
-  s>     commands require POST requests
-
-SSL required by default
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/rw/customreadonly
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 403 ssl required\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Length: 17\r\n
-  s>     \r\n
-  s>     permission denied
-
-Restart server to allow non-ssl read-write operations
-
-  $ killdaemons.py
-  $ cat > server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > web.api.http-v2 = true
-  > [web]
-  > push_ssl = false
-  > allow-push = *
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Authorized request for valid read-write command works
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/rw/customreadonly
-  >     user-agent: test
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     content-length: 29\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     27\r\n
-  s>     \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-
-Authorized request for unknown command is rejected
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/rw/badcommand
-  >     user-agent: test
-  >     accept: $MEDIATYPE
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/rw/badcommand HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 42\r\n
-  s>     \r\n
-  s>     unknown wire protocol command: badcommand\n
-
-debugreflect isn't enabled by default
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/debugreflect
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/debugreflect HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 34\r\n
-  s>     \r\n
-  s>     debugreflect service not available
-
-Restart server to get debugreflect endpoint
-
-  $ killdaemons.py
-  $ cat > server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > web.api.debugreflect = true
-  > web.api.http-v2 = true
-  > [web]
-  > push_ssl = false
-  > allow-push = *
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Command frames can be reflected via debugreflect
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/debugreflect
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     user-agent: test
-  >     frame 1 1 stream-begin command-request new cbor:{b'name': b'command1', b'args': {b'foo': b'val1', b'bar1': b'val'}}
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/debugreflect HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     content-length: 47\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \'\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa2Dbar1CvalCfooDval1DnameHcommand1
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 223\r\n
-  s>     \r\n
-  s>     received: 1 1 1 \xa2Dargs\xa2Dbar1CvalCfooDval1DnameHcommand1\n
-  s>     ["runcommand", {"args": {"bar1": "val", "foo": "val1"}, "command": "command1", "data": null, "redirect": null, "requestid": 1}]\n
-  s>     received: <no frame>\n
-  s>     {"action": "noop"}
-
-Multiple requests to regular command URL are not allowed
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/customreadonly
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     user-agent: test
-  >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     content-length: 29\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     27\r\n
-  s>     \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-
-Multiple requests to "multirequest" URL are allowed
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/multirequest
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     user-agent: test
-  >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
-  >     frame 3 1 0 command-request new cbor:{b'name': b'customreadonly'}
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     *\r\n (glob)
-  s>     *\r\n (glob)
-  s>     user-agent: test\r\n
-  s>     content-length: 58\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \x15\x00\x00\x01\x00\x01\x01\x11\xa1DnameNcustomreadonly\x15\x00\x00\x03\x00\x01\x00\x11\xa1DnameNcustomreadonly
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     27\r\n
-  s>     \x1f\x00\x00\x01\x00\x02\x041X\x1dcustomreadonly bytes response
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x03\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     27\r\n
-  s>     \x1f\x00\x00\x03\x00\x02\x041X\x1dcustomreadonly bytes response
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x03\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-
-Interleaved requests to "multirequest" are processed
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/multirequest
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     user-agent: test
-  >     frame 1 1 stream-begin command-request new|more \xa2Dargs\xa1Inamespace
-  >     frame 3 1 0 command-request new|more \xa2Dargs\xa1Inamespace
-  >     frame 3 1 0 command-request continuation JnamespacesDnameHlistkeys
-  >     frame 1 1 0 command-request continuation IbookmarksDnameHlistkeys
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     content-length: 115\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \x11\x00\x00\x01\x00\x01\x01\x15\xa2Dargs\xa1Inamespace\x11\x00\x00\x03\x00\x01\x00\x15\xa2Dargs\xa1Inamespace\x19\x00\x00\x03\x00\x01\x00\x12JnamespacesDnameHlistkeys\x18\x00\x00\x01\x00\x01\x00\x12IbookmarksDnameHlistkeys
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x03\x00\x02\x01\x92Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x03\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     28\r\n
-  s>      \x00\x00\x03\x00\x02\x041\xa3Ibookmarks@Jnamespaces@Fphases@
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x03\x00\x02\x002
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041\xa1FstatusBok
-  s>     \r\n
-  s>     9\r\n
-  s>     \x01\x00\x00\x01\x00\x02\x041\xa0
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-
-Restart server to disable read-write access
-
-  $ killdaemons.py
-  $ cat > server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > web.api.debugreflect = true
-  > web.api.http-v2 = true
-  > [web]
-  > push_ssl = false
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Attempting to run a read-write command via multirequest on read-only URL is not allowed
-
-  $ sendhttpraw << EOF
-  > httprequest POST api/$HTTPV2/ro/multirequest
-  >     accept: $MEDIATYPE
-  >     content-type: $MEDIATYPE
-  >     user-agent: test
-  >     frame 1 1 stream-begin command-request new cbor:{b'name': b'pushkey'}
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     user-agent: test\r\n
-  s>     content-length: 22\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s>     \x0e\x00\x00\x01\x00\x01\x01\x11\xa1DnameGpushkey
-  s> makefile('rb', None)
-  s>     HTTP/1.1 403 Forbidden\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 52\r\n
-  s>     \r\n
-  s>     insufficient permissions to execute command: pushkey
-
-Defining an invalid content encoding results in warning
-
-  $ hg --config experimental.httppeer.v2-encoder-order=identity,badencoder --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ << EOF
-  > command heads
-  > EOF
-  creating http peer for wire protocol version 2
-  sending heads command
-  wire protocol version 2 encoder referenced in config (badencoder) is not known; ignoring
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 56\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     1e\r\n
-  s>     \x16\x00\x00\x01\x00\x02\x041
-  s>     \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: [
-    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-#if zstd
-
-  $ hg --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/ << EOF
-  > command heads
-  > EOF
-  creating http peer for wire protocol version 2
-  sending heads command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 70\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     *\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x83Hzstd-8mbDzlibHidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hzstd-8mb
-  s>     \r\n
-  s>     25\r\n
-  s>     \x1d\x00\x00\x01\x00\x02\x042
-  s>     (\xb5/\xfd\x00X\xa4\x00\x00p\xa1FstatusBok\x81T\x00\x01\x00\tP\x02
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: [
-    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-#endif
-
-  $ cat error.log
--- a/tests/test-http-api.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,299 +0,0 @@
-#require no-chg
-
-  $ send() {
-  >   hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/
-  > }
-
-  $ hg init server
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid
-  $ cat hg.pid > $DAEMON_PIDS
-
-Request to /api fails unless web.apiserver is enabled
-
-  $ get-with-headers.py $LOCALIP:$HGPORT api
-  400 no such method: api
-  
-  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-  <head>
-  <link rel="icon" href="/static/hgicon.png" type="image/png" />
-  <meta name="robots" content="index, nofollow" />
-  <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
-  <script type="text/javascript" src="/static/mercurial.js"></script>
-  
-  <title>$TESTTMP/server: error</title>
-  </head>
-  <body>
-  
-  <div class="container">
-  <div class="menu">
-  <div class="logo">
-  <a href="https://mercurial-scm.org/">
-  <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
-  </div>
-  <ul>
-  <li><a href="/shortlog">log</a></li>
-  <li><a href="/graph">graph</a></li>
-  <li><a href="/tags">tags</a></li>
-  <li><a href="/bookmarks">bookmarks</a></li>
-  <li><a href="/branches">branches</a></li>
-  </ul>
-  <ul>
-  <li><a href="/help">help</a></li>
-  </ul>
-  </div>
-  
-  <div class="main">
-  
-  <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
-  <h3>error</h3>
-  
-  
-  <form class="search" action="/log">
-  
-  <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
-  <div id="hint">Find changesets by keywords (author, files, the commit message), revision
-  number or hash, or <a href="/help/revsets">revset expression</a>.</div>
-  </form>
-  
-  <div class="description">
-  <p>
-  An error occurred while processing your request:
-  </p>
-  <p>
-  no such method: api
-  </p>
-  </div>
-  </div>
-  </div>
-  
-  
-  
-  </body>
-  </html>
-  
-  [1]
-
-  $ get-with-headers.py $LOCALIP:$HGPORT api/
-  400 no such method: api
-  
-  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
-  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
-  <head>
-  <link rel="icon" href="/static/hgicon.png" type="image/png" />
-  <meta name="robots" content="index, nofollow" />
-  <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
-  <script type="text/javascript" src="/static/mercurial.js"></script>
-  
-  <title>$TESTTMP/server: error</title>
-  </head>
-  <body>
-  
-  <div class="container">
-  <div class="menu">
-  <div class="logo">
-  <a href="https://mercurial-scm.org/">
-  <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
-  </div>
-  <ul>
-  <li><a href="/shortlog">log</a></li>
-  <li><a href="/graph">graph</a></li>
-  <li><a href="/tags">tags</a></li>
-  <li><a href="/bookmarks">bookmarks</a></li>
-  <li><a href="/branches">branches</a></li>
-  </ul>
-  <ul>
-  <li><a href="/help">help</a></li>
-  </ul>
-  </div>
-  
-  <div class="main">
-  
-  <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
-  <h3>error</h3>
-  
-  
-  <form class="search" action="/log">
-  
-  <p><input name="rev" id="search1" type="text" size="30" value="" /></p>
-  <div id="hint">Find changesets by keywords (author, files, the commit message), revision
-  number or hash, or <a href="/help/revsets">revset expression</a>.</div>
-  </form>
-  
-  <div class="description">
-  <p>
-  An error occurred while processing your request:
-  </p>
-  <p>
-  no such method: api
-  </p>
-  </div>
-  </div>
-  </div>
-  
-  
-  
-  </body>
-  </html>
-  
-  [1]
-
-Restart server with support for API server
-
-  $ killdaemons.py
-  $ cat > server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid
-  $ cat hg.pid > $DAEMON_PIDS
-
-/api lists available APIs (empty since none are available by default)
-
-  $ send << EOF
-  > httprequest GET api
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 100\r\n
-  s>     \r\n
-  s>     APIs can be accessed at /api/<name>, where <name> can be one of the following:\n
-  s>     \n
-  s>     (no available APIs)\n
-
-  $ send << EOF
-  > httprequest GET api/
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/ HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 100\r\n
-  s>     \r\n
-  s>     APIs can be accessed at /api/<name>, where <name> can be one of the following:\n
-  s>     \n
-  s>     (no available APIs)\n
-
-Accessing an unknown API yields a 404
-
-  $ send << EOF
-  > httprequest GET api/unknown
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/unknown HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 33\r\n
-  s>     \r\n
-  s>     Unknown API: unknown\n
-  s>     Known APIs: 
-
-Accessing a known but not enabled API yields a different error
-
-  $ send << EOF
-  > httprequest GET api/exp-http-v2-0003
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/exp-http-v2-0003 HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 33\r\n
-  s>     \r\n
-  s>     API exp-http-v2-0003 not enabled\n
-
-Restart server with support for HTTP v2 API
-
-  $ killdaemons.py
-  $ cat > server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > web.api.http-v2 = true
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid
-  $ cat hg.pid > $DAEMON_PIDS
-
-/api lists the HTTP v2 protocol as available
-
-  $ send << EOF
-  > httprequest GET api
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 96\r\n
-  s>     \r\n
-  s>     APIs can be accessed at /api/<name>, where <name> can be one of the following:\n
-  s>     \n
-  s>     exp-http-v2-0003
-
-  $ send << EOF
-  > httprequest GET api/
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/ HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 96\r\n
-  s>     \r\n
-  s>     APIs can be accessed at /api/<name>, where <name> can be one of the following:\n
-  s>     \n
-  s>     exp-http-v2-0003
--- a/tests/test-http-protocol.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-http-protocol.t	Tue Dec 07 16:44:22 2021 +0100
@@ -252,121 +252,6 @@
   s>     bookmarks\t\n
   s>     namespaces\t\n
   s>     phases\t
-
-Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
-
-  $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
-  > command heads
-  > EOF
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 Script output follows\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-0.1\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  sending heads command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=heads HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1\r\n
-  s>     x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 Script output follows\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-0.1\r\n
-  s>     Content-Length: 41\r\n
-  s>     \r\n
-  s>     0000000000000000000000000000000000000000\n
-  response: [
-    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ killdaemons.py
-  $ enablehttpv2 empty
-  $ hg --config server.compressionengines=zlib -R empty serve -p $HGPORT -d --pid-file hg.pid
-  $ cat hg.pid > $DAEMON_PIDS
-
-Client with HTTPv2 enabled automatically upgrades if the server supports it
-
-  $ hg --config experimental.httppeer.advertise-v2=true --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
-  > command heads
-  > EOF
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogNv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  sending heads command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 56\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x0c\x00\x00\x01\x00\x01\x00\x11\xa1DnameEheads
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     1e\r\n
-  s>     \x16\x00\x00\x01\x00\x02\x041
-  s>     \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: [
-    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
   $ killdaemons.py
 
 HTTP client follows HTTP redirect on handshake to new repo
--- a/tests/test-largefiles-wireproto.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-largefiles-wireproto.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,13 +1,3 @@
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
 This file contains testcases that tend to be related to the wire protocol part
 of largefiles.
 
--- a/tests/test-pull-network.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-pull-network.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,15 +1,5 @@
 #require serve
 
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
   $ hg init test
   $ cd test
 
--- a/tests/test-ssh-bundle1.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-ssh-bundle1.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,16 +1,6 @@
 This test is a duplicate of 'test-http.t' feel free to factor out
 parts that are not bundle1/bundle2 specific.
 
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
   $ cat << EOF >> $HGRCPATH
   > [devel]
   > # This test is dedicated to interaction through old bundle
@@ -483,15 +473,13 @@
   $ hg pull --debug ssh://user@dummy/remote
   pulling from ssh://user@dummy/remote
   running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R remote serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
-  remote: 444 (sshv1 no-rust !)
-  remote: 463 (sshv1 rust !)
-  protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
+  remote: 444 (no-rust !)
+  remote: 463 (rust !)
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (no-rust !)
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,persistent-nodemap,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (rust !)
-  remote: 1 (sshv1 !)
+  remote: 1
   sending protocaps command
   preparing listkeys for "bookmarks"
   sending listkeys command
--- a/tests/test-ssh-clone-r.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-ssh-clone-r.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,15 +1,5 @@
 This test tries to exercise the ssh functionality with a dummy script
 
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
 creating 'remote' repo
 
   $ hg init remote
--- a/tests/test-ssh-proto-unbundle.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-ssh-proto-unbundle.t	Tue Dec 07 16:44:22 2021 +0100
@@ -5,13 +5,6 @@
   > use-persistent-nodemap = no
   > EOF
 
-  $ cat > hgrc-sshv2 << EOF
-  > %include $HGRCPATH
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-
   $ debugwireproto() {
   >   commands=`cat -`
   >   echo 'testing ssh1'
@@ -20,12 +13,6 @@
   >   if [ -n "$1" ]; then
   >       hg --config extensions.strip= strip --no-backup -r "all() - ::${tip}"
   >   fi
-  >   echo ""
-  >   echo 'testing ssh2'
-  >   echo "${commands}" | HGRCPATH=$TESTTMP/hgrc-sshv2 hg --verbose debugwireproto --localssh --noreadstderr
-  >   if [ -n "$1" ]; then
-  >       hg --config extensions.strip= strip --no-backup -r "all() - ::${tip}"
-  >   fi
   > }
 
 Generate some bundle files
@@ -103,56 +90,6 @@
   e> read(-1) -> 115:
   e>     abort: incompatible Mercurial client; bundle2 required\n
   e>     (see https://www.mercurial-scm.org/wiki/IncompatibleClient)\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 115:
-  e>     abort: incompatible Mercurial client; bundle2 required\n
-  e>     (see https://www.mercurial-scm.org/wiki/IncompatibleClient)\n
 
   $ cd ..
 
@@ -287,61 +224,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 151:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     ui.write 1 line\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 And a variation that writes multiple lines using ui.write
 
@@ -412,62 +294,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 173:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     ui.write 2 lines 1\n
-  e>     ui.write 2 lines 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 And a variation that does a ui.flush() after writing output
 
@@ -537,61 +363,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 157:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     ui.write 1 line flush\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 Multiple writes + flush
 
@@ -662,62 +433,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 161:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     ui.write 1st\n
-  e>     ui.write 2nd\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 ui.write() + ui.write_err() output is captured
 
@@ -790,64 +505,7 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 187:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     ui.write 1\n
-  e>     ui.write_err 1\n
-  e>     ui.write 2\n
-  e>     ui.write_err 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
+
 
 print() output is captured
 
@@ -917,61 +575,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 148:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     printed line\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 Mixed print() and ui.write() are both captured
 
@@ -1044,64 +647,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 173:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     print 1\n
-  e>     ui.write 1\n
-  e>     print 2\n
-  e>     ui.write 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 print() to stdout and stderr both get captured
 
@@ -1174,64 +719,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 171:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     stdout 1\n
-  e>     stderr 1\n
-  e>     stdout 2\n
-  e>     stderr 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook failed\n
 
 Shell hook writing to stdout has output captured
 
@@ -1308,63 +795,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook exited with status 1\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 167:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     stdout 1\n
-  e>     stdout 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook exited with status 1\n
-
 Shell hook writing to stderr has output captured
 
   $ cat > $TESTTMP/hook.sh << EOF
@@ -1435,63 +865,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook exited with status 1\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 167:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     stderr 1\n
-  e>     stderr 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook exited with status 1\n
-
 Shell hook writing to stdout and stderr has output captured
 
   $ cat > $TESTTMP/hook.sh << EOF
@@ -1566,65 +939,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.fail hook exited with status 1\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 185:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     stdout 1\n
-  e>     stderr 1\n
-  e>     stdout 2\n
-  e>     stderr 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.fail hook exited with status 1\n
-
 Shell and Python hooks writing to stdout and stderr have output captured
 
   $ cat > $TESTTMP/hook.sh << EOF
@@ -1709,69 +1023,6 @@
   e>     transaction abort!\n
   e>     rollback completed\n
   e>     abort: pretxnchangegroup.b hook failed\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 0
-  result: 0
-  remote output: 
-  e> read(-1) -> 228:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     shell stdout 1\n
-  e>     shell stderr 1\n
-  e>     shell stdout 2\n
-  e>     shell stderr 2\n
-  e>     stdout 1\n
-  e>     stderr 1\n
-  e>     stdout 2\n
-  e>     stderr 2\n
-  e>     transaction abort!\n
-  e>     rollback completed\n
-  e>     abort: pretxnchangegroup.b hook failed\n
-
   $ cd ..
 
 Pushing a bundle1 with no output
@@ -1837,59 +1088,6 @@
   e>     adding manifests\n
   e>     adding file changes\n
   e>     added 1 changesets with 1 changes to 1 files\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 1
-  result: 1
-  remote output: 
-  e> read(-1) -> 100:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     added 1 changesets with 1 changes to 1 files\n
-
   $ cd ..
 
 Pushing a bundle1 with ui.write() and ui.write_err()
@@ -1971,59 +1169,3 @@
   e>     ui.write 2\n
   e>     ui.write_err 2\n
   e>     added 1 changesets with 1 changes to 1 files\n
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending unbundle command
-  i> write(9) -> 9:
-  i>     unbundle\n
-  i> write(9) -> 9:
-  i>     heads 10\n
-  i> write(10) -> 10: 666f726365
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  i> write(4) -> 4:
-  i>     426\n
-  i> write(426) -> 426:
-  i>     HG10UN\x00\x00\x00\x9eh\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00>cba485ca3678256e044428f70f58291196f6e9de\n
-  i>     test\n
-  i>     0 0\n
-  i>     foo\n
-  i>     \n
-  i>     initial\x00\x00\x00\x00\x00\x00\x00\x8d\xcb\xa4\x85\xca6x%n\x04D(\xf7\x0fX)\x11\x96\xf6\xe9\xde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00-foo\x00362fef284ce2ca02aecc8de6d5e8a1c3af0556fe\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x07foo\x00\x00\x00b6/\xef(L\xe2\xca\x02\xae\xcc\x8d\xe6\xd5\xe8\xa1\xc3\xaf\x05V\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00h\x98b\x13\xbdD\x85\xeaQS55\xe3\xfc\x9ex\x00zq\x1f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x020\n
-  i>     \x00\x00\x00\x00\x00\x00\x00\x00
-  i> write(2) -> 2:
-  i>     0\n
-  i> flush() -> None
-  o> readline() -> 2:
-  o>     0\n
-  o> readline() -> 2:
-  o>     1\n
-  o> read(1) -> 1: 1
-  result: 1
-  remote output: 
-  e> read(-1) -> 152:
-  e>     adding changesets\n
-  e>     adding manifests\n
-  e>     adding file changes\n
-  e>     ui.write 1\n
-  e>     ui.write_err 1\n
-  e>     ui.write 2\n
-  e>     ui.write_err 2\n
-  e>     added 1 changesets with 1 changes to 1 files\n
--- a/tests/test-ssh-proto.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-ssh-proto.t	Tue Dec 07 16:44:22 2021 +0100
@@ -7,13 +7,6 @@
   > use-persistent-nodemap = no
   > EOF
 
-  $ cat > hgrc-sshv2 << EOF
-  > %include $HGRCPATH
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-
 Helper function to run protocol tests against multiple protocol versions.
 This is easier than using #testcases because managing differences between
 protocols with inline conditional output is hard to read.
@@ -22,9 +15,6 @@
   >   commands=`cat -`
   >   echo 'testing ssh1'
   >   echo "${commands}" | hg --verbose debugwireproto --localssh
-  >   echo ""
-  >   echo 'testing ssh2'
-  >   echo "${commands}" | HGRCPATH=$TESTTMP/hgrc-sshv2 hg --verbose debugwireproto --localssh
   > }
 
   $ cat >> $HGRCPATH << EOF
@@ -54,9 +44,6 @@
   $ hg debugwireproto --localssh --peer ssh1 << EOF
   > EOF
   creating ssh peer for wire protocol version 1
-  $ hg debugwireproto --localssh --peer ssh2 << EOF
-  > EOF
-  creating ssh peer for wire protocol version 2
 
 Test a normal behaving server, for sanity
 
@@ -916,410 +903,6 @@
   o> readline() -> 4:
   o>     444\n
 
-Send an upgrade request to a server that doesn't support that command
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n
-  > readline
-  > raw
-  >     hello\n
-  >     between\n
-  >     pairs 81\n
-  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  > readline
-  > readline
-  > readline
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(77) -> 77:
-  i>     upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n
-  o> readline() -> 2:
-  o>     0\n
-  i> write(104) -> 104:
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  o> readline() -> 4:
-  o>     444\n
-  o> readline() -> 444:
-  o>     capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
-  o> readline() -> 2:
-  o>     1\n
-  o> readline() -> 1:
-  o>     \n
-
-  $ cd ..
-
-  $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server
-  running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R server serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob)
-  devel-peer-request: hello+between
-  devel-peer-request:   pairs: 81 bytes
-  sending hello command
-  sending between command
-  remote: 0
-  remote: 444
-  remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  remote: 1
-  devel-peer-request: protocaps
-  devel-peer-request:   caps: * bytes (glob)
-  sending protocaps command
-  url: ssh://user@dummy/server
-  local: no
-  pushable: yes
-
-Enable version 2 support on server. We need to do this in hgrc because we can't
-use --config with `hg serve --stdio`.
-
-  $ cat >> server/.hg/hgrc << EOF
-  > [experimental]
-  > sshserver.support-v2 = true
-  > EOF
-
-Send an upgrade request to a server that supports upgrade
-
-  $ cd server
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
-  >     hello\n
-  >     between\n
-  >     pairs 81\n
-  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  > readline
-  > readline
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(153) -> 153:
-  i>     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  o> readline() -> 44:
-  o>     upgraded this-is-some-token exp-ssh-v2-0003\n
-  o> readline() -> 4:
-  o>     443\n
-  o> readline() -> 444:
-  o>     capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
-
-  $ cd ..
-
-  $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server
-  running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R server serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob)
-  devel-peer-request: hello+between
-  devel-peer-request:   pairs: 81 bytes
-  sending hello command
-  sending between command
-  protocol upgraded to exp-ssh-v2-0003
-  remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  devel-peer-request: protocaps
-  devel-peer-request:   caps: * bytes (glob)
-  sending protocaps command
-  url: ssh://user@dummy/server
-  local: no
-  pushable: yes
-
-Verify the peer has capabilities
-
-  $ hg --config experimental.sshpeer.advertise-v2=true --debug debugcapabilities ssh://user@dummy/server
-  running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R server serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob)
-  devel-peer-request: hello+between
-  devel-peer-request:   pairs: 81 bytes
-  sending hello command
-  sending between command
-  protocol upgraded to exp-ssh-v2-0003
-  remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  devel-peer-request: protocaps
-  devel-peer-request:   caps: * bytes (glob)
-  sending protocaps command
-  Main capabilities:
-    batch
-    branchmap
-    $USUAL_BUNDLE2_CAPS$
-    changegroupsubset
-    getbundle
-    known
-    lookup
-    protocaps
-    pushkey
-    streamreqs=generaldelta,revlogv1,sparserevlog
-    unbundle=HG10GZ,HG10BZ,HG10UN
-    unbundlehash
-  Bundle2 capabilities:
-    HG20
-    bookmarks
-    changegroup
-      01
-      02
-    checkheads
-      related
-    digests
-      md5
-      sha1
-      sha512
-    error
-      abort
-      unsupportedcontent
-      pushraced
-      pushkey
-    hgtagsfnodes
-    listkeys
-    phases
-      heads
-    pushkey
-    remote-changegroup
-      http
-      https
-    stream
-      v2
-
-Command after upgrade to version 2 is processed
-
-  $ cd server
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >      upgrade this-is-some-token proto=exp-ssh-v2-0003\n
-  >      hello\n
-  >      between\n
-  >      pairs 81\n
-  >      0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  > readline
-  > readline
-  > readline
-  > raw
-  >      hello\n
-  > readline
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(153) -> 153:
-  i>     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  o> readline() -> 44:
-  o>     upgraded this-is-some-token exp-ssh-v2-0003\n
-  o> readline() -> 4:
-  o>     443\n
-  o> readline() -> 444:
-  o>     capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
-  i> write(6) -> 6:
-  i>     hello\n
-  o> readline() -> 4:
-  o>     428\n
-  o> readline() -> 428:
-  o>     capabilities: branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
-
-Multiple upgrades is not allowed
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
-  >     hello\n
-  >     between\n
-  >     pairs 81\n
-  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  > readline
-  > readline
-  > readline
-  > raw
-  >     upgrade another-token proto=irrelevant\n
-  >     hello\n
-  > readline
-  > readavailable
-  > EOF
-  using raw connection to peer
-  i> write(153) -> 153:
-  i>     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  o> readline() -> 44:
-  o>     upgraded this-is-some-token exp-ssh-v2-0003\n
-  o> readline() -> 4:
-  o>     443\n
-  o> readline() -> 444:
-  o>     capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
-  i> write(45) -> 45:
-  i>     upgrade another-token proto=irrelevant\n
-  i>     hello\n
-  o> readline() -> 1:
-  o>     \n
-  e> read(-1) -> 42:
-  e>     cannot upgrade protocols multiple times\n
-  e>     -\n
-
-Malformed upgrade request line (not exactly 3 space delimited tokens)
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade\n
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(8) -> 8:
-  i>     upgrade\n
-  o> readline() -> 2:
-  o>     0\n
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade token\n
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(14) -> 14:
-  i>     upgrade token\n
-  o> readline() -> 2:
-  o>     0\n
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade token foo=bar extra-token\n
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(34) -> 34:
-  i>     upgrade token foo=bar extra-token\n
-  o> readline() -> 2:
-  o>     0\n
-
-Upgrade request to unsupported protocol is ignored
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade this-is-some-token proto=unknown1,unknown2\n
-  > readline
-  > raw
-  >     hello\n
-  > readline
-  > readline
-  > raw
-  >     between\n
-  >     pairs 81\n
-  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  > readline
-  > readline
-  > EOF
-  using raw connection to peer
-  i> write(51) -> 51:
-  i>     upgrade this-is-some-token proto=unknown1,unknown2\n
-  o> readline() -> 2:
-  o>     0\n
-  i> write(6) -> 6:
-  i>     hello\n
-  o> readline() -> 4:
-  o>     444\n
-  o> readline() -> 444:
-  o>     capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash\n
-  i> write(98) -> 98:
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  o> readline() -> 2:
-  o>     1\n
-  o> readline() -> 1:
-  o>     \n
-
-Upgrade request must be followed by hello + between
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade token proto=exp-ssh-v2-0003\n
-  >     invalid\n
-  > readline
-  > readavailable
-  > EOF
-  using raw connection to peer
-  i> write(44) -> 44:
-  i>     upgrade token proto=exp-ssh-v2-0003\n
-  i>     invalid\n
-  o> readline() -> 1:
-  o>     \n
-  e> read(-1) -> 46:
-  e>     malformed handshake protocol: missing hello\n
-  e>     -\n
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade token proto=exp-ssh-v2-0003\n
-  >     hello\n
-  >     invalid\n
-  > readline
-  > readavailable
-  > EOF
-  using raw connection to peer
-  i> write(50) -> 50:
-  i>     upgrade token proto=exp-ssh-v2-0003\n
-  i>     hello\n
-  i>     invalid\n
-  o> readline() -> 1:
-  o>     \n
-  e> read(-1) -> 48:
-  e>     malformed handshake protocol: missing between\n
-  e>     -\n
-
-  $ hg debugwireproto --localssh --peer raw << EOF
-  > raw
-  >     upgrade token proto=exp-ssh-v2-0003\n
-  >     hello\n
-  >     between\n
-  >     invalid\n
-  > readline
-  > readavailable
-  > EOF
-  using raw connection to peer
-  i> write(58) -> 58:
-  i>     upgrade token proto=exp-ssh-v2-0003\n
-  i>     hello\n
-  i>     between\n
-  i>     invalid\n
-  o> readline() -> 1:
-  o>     \n
-  e> read(-1) -> 49:
-  e>     malformed handshake protocol: missing pairs 81\n
-  e>     -\n
-
-Legacy commands are not exposed to version 2 of protocol
-
-TODO re-enable these once we're back to actually using v2 commands
-
-$ hg --config experimental.sshpeer.advertise-v2=true debugwireproto --localssh << EOF
-> command branches
->     nodes 0000000000000000000000000000000000000000
-> EOF
-creating ssh peer from handshake results
-sending branches command
-response:
-
-$ hg --config experimental.sshpeer.advertise-v2=true debugwireproto --localssh << EOF
-> command changegroup
->     roots 0000000000000000000000000000000000000000
-> EOF
-creating ssh peer from handshake results
-sending changegroup command
-response:
-
-$ hg --config experimental.sshpeer.advertise-v2=true debugwireproto --localssh << EOF
-> command changegroupsubset
->     bases 0000000000000000000000000000000000000000
->     heads 0000000000000000000000000000000000000000
-> EOF
-creating ssh peer from handshake results
-sending changegroupsubset command
-response:
-
   $ cd ..
 
 Test listkeys for listing namespaces
@@ -1364,41 +947,6 @@
     b'namespaces': b'',
     b'phases': b''
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(13) -> 13:
-  i>     namespace 10\n
-  i> write(10) -> 10: namespaces
-  i> flush() -> None
-  o> bufferedreadline() -> 3:
-  o>     30\n
-  o> bufferedread(30) -> 30:
-  o>     bookmarks\t\n
-  o>     namespaces\t\n
-  o>     phases\t
-  response: {
-    b'bookmarks': b'',
-    b'namespaces': b'',
-    b'phases': b''
-  }
 
   $ cd ..
 
@@ -1444,33 +992,6 @@
   o> bufferedreadline() -> 2:
   o>     0\n
   response: {}
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 9\n
-  i> write(9) -> 9: bookmarks
-  i> flush() -> None
-  o> bufferedreadline() -> 2:
-  o>     0\n
-  response: {}
 
 With a single bookmark set
 
@@ -1508,36 +1029,6 @@
   response: {
     b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f'
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 9\n
-  i> write(9) -> 9: bookmarks
-  i> flush() -> None
-  o> bufferedreadline() -> 3:
-  o>     46\n
-  o> bufferedread(46) -> 46: bookA\t68986213bd4485ea51533535e3fc9e78007a711f
-  response: {
-    b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f'
-  }
 
 With multiple bookmarks set
 
@@ -1578,39 +1069,6 @@
     b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f',
     b'bookB': b'1880f3755e2e52e3199e0ee5638128b08642f34d'
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 9\n
-  i> write(9) -> 9: bookmarks
-  i> flush() -> None
-  o> bufferedreadline() -> 3:
-  o>     93\n
-  o> bufferedread(93) -> 93:
-  o>     bookA\t68986213bd4485ea51533535e3fc9e78007a711f\n
-  o>     bookB\t1880f3755e2e52e3199e0ee5638128b08642f34d
-  response: {
-    b'bookA': b'68986213bd4485ea51533535e3fc9e78007a711f',
-    b'bookB': b'1880f3755e2e52e3199e0ee5638128b08642f34d'
-  }
 
 Test pushkey for bookmarks
 
@@ -1657,43 +1115,6 @@
   o> bufferedread(2) -> 2:
   o>     1\n
   response: True
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending pushkey command
-  i> write(8) -> 8:
-  i>     pushkey\n
-  i> write(6) -> 6:
-  i>     key 6\n
-  i> write(6) -> 6: remote
-  i> write(12) -> 12:
-  i>     namespace 9\n
-  i> write(9) -> 9: bookmarks
-  i> write(7) -> 7:
-  i>     new 40\n
-  i> write(40) -> 40: 68986213bd4485ea51533535e3fc9e78007a711f
-  i> write(6) -> 6:
-  i>     old 0\n
-  i> flush() -> None
-  o> bufferedreadline() -> 2:
-  o>     2\n
-  o> bufferedread(2) -> 2:
-  o>     1\n
-  response: True
 
   $ hg bookmarks
      bookA                     0:68986213bd44
@@ -1742,36 +1163,6 @@
   response: {
     b'publishing': b'True'
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 6\n
-  i> write(6) -> 6: phases
-  i> flush() -> None
-  o> bufferedreadline() -> 3:
-  o>     15\n
-  o> bufferedread(15) -> 15: publishing\tTrue
-  response: {
-    b'publishing': b'True'
-  }
 
 Create some commits
 
@@ -1830,41 +1221,6 @@
     b'c4750011d906c18ea2f0527419cbc1a544435150': b'1',
     b'publishing': b'True'
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 6\n
-  i> write(6) -> 6: phases
-  i> flush() -> None
-  o> bufferedreadline() -> 4:
-  o>     101\n
-  o> bufferedread(101) -> 101:
-  o>     20b8a89289d80036e6c4e87c2083e3bea1586637\t1\n
-  o>     c4750011d906c18ea2f0527419cbc1a544435150\t1\n
-  o>     publishing\tTrue
-  response: {
-    b'20b8a89289d80036e6c4e87c2083e3bea1586637': b'1',
-    b'c4750011d906c18ea2f0527419cbc1a544435150': b'1',
-    b'publishing': b'True'
-  }
 
 Single draft head
 
@@ -1905,39 +1261,6 @@
     b'c4750011d906c18ea2f0527419cbc1a544435150': b'1',
     b'publishing': b'True'
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 6\n
-  i> write(6) -> 6: phases
-  i> flush() -> None
-  o> bufferedreadline() -> 3:
-  o>     58\n
-  o> bufferedread(58) -> 58:
-  o>     c4750011d906c18ea2f0527419cbc1a544435150\t1\n
-  o>     publishing\tTrue
-  response: {
-    b'c4750011d906c18ea2f0527419cbc1a544435150': b'1',
-    b'publishing': b'True'
-  }
 
 All public heads
 
@@ -1975,36 +1298,6 @@
   response: {
     b'publishing': b'True'
   }
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending listkeys command
-  i> write(9) -> 9:
-  i>     listkeys\n
-  i> write(12) -> 12:
-  i>     namespace 6\n
-  i> write(6) -> 6: phases
-  i> flush() -> None
-  o> bufferedreadline() -> 3:
-  o>     15\n
-  o> bufferedread(15) -> 15: publishing\tTrue
-  response: {
-    b'publishing': b'True'
-  }
 
 Setting public phase via pushkey
 
@@ -2054,44 +1347,6 @@
   o> bufferedread(2) -> 2:
   o>     1\n
   response: True
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending pushkey command
-  i> write(8) -> 8:
-  i>     pushkey\n
-  i> write(7) -> 7:
-  i>     key 40\n
-  i> write(40) -> 40: 7127240a084fd9dc86fe8d1f98e26229161ec82b
-  i> write(12) -> 12:
-  i>     namespace 6\n
-  i> write(6) -> 6: phases
-  i> write(6) -> 6:
-  i>     new 1\n
-  i> write(1) -> 1: 0
-  i> write(6) -> 6:
-  i>     old 1\n
-  i> write(1) -> 1: 1
-  i> flush() -> None
-  o> bufferedreadline() -> 2:
-  o>     2\n
-  o> bufferedread(2) -> 2:
-  o>     1\n
-  response: True
 
   $ hg phase .
   4: public
@@ -2160,40 +1415,3 @@
   response #0: bfebe6bd38eebc6f8202e419c1171268987ea6a6 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n
   response #1: bookA\t4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\nbookB\tbfebe6bd38eebc6f8202e419c1171268987ea6a6
   response #2: 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\t1\nbfebe6bd38eebc6f8202e419c1171268987ea6a6\t1\npublishing\tTrue
-  
-  testing ssh2
-  creating ssh peer from handshake results
-  i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
-  i>     hello\n
-  i>     between\n
-  i>     pairs 81\n
-  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
-  i> flush() -> None
-  o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0003\n (glob)
-  o> readline() -> 4:
-  o>     443\n
-  o> read(443) -> 443: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  o> read(1) -> 1:
-  o>     \n
-  sending batch with 3 sub-commands
-  i> write(6) -> 6:
-  i>     batch\n
-  i> write(4) -> 4:
-  i>     * 0\n
-  i> write(8) -> 8:
-  i>     cmds 61\n
-  i> write(61) -> 61: heads ;listkeys namespace=bookmarks;listkeys namespace=phases
-  i> flush() -> None
-  o> bufferedreadline() -> 4:
-  o>     278\n
-  o> bufferedread(278) -> 278:
-  o>     bfebe6bd38eebc6f8202e419c1171268987ea6a6 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n
-  o>     ;bookA\t4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n
-  o>     bookB\tbfebe6bd38eebc6f8202e419c1171268987ea6a6;4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\t1\n
-  o>     bfebe6bd38eebc6f8202e419c1171268987ea6a6\t1\n
-  o>     publishing\tTrue
-  response #0: bfebe6bd38eebc6f8202e419c1171268987ea6a6 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\n
-  response #1: bookA\t4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\nbookB\tbfebe6bd38eebc6f8202e419c1171268987ea6a6
-  response #2: 4ee3fcef1c800fa2bf23e20af7c83ff111d9c7ab\t1\nbfebe6bd38eebc6f8202e419c1171268987ea6a6\t1\npublishing\tTrue
--- a/tests/test-ssh.t	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/test-ssh.t	Tue Dec 07 16:44:22 2021 +0100
@@ -1,13 +1,3 @@
-#testcases sshv1 sshv2
-
-#if sshv2
-  $ cat >> $HGRCPATH << EOF
-  > [experimental]
-  > sshpeer.advertise-v2 = true
-  > sshserver.support-v2 = true
-  > EOF
-#endif
-
 This test tries to exercise the ssh functionality with a dummy script
 
 creating 'remote' repo
@@ -537,17 +527,15 @@
   $ hg pull --debug ssh://user@dummy/remote --config devel.debug.peer-request=yes
   pulling from ssh://user@dummy/remote
   running .* ".*[/\\]dummyssh" ['"]user@dummy['"] ['"]hg -R remote serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   devel-peer-request: hello+between
   devel-peer-request:   pairs: 81 bytes
   sending hello command
   sending between command
-  remote: 444 (sshv1 no-rust !)
-  remote: 463 (sshv1 rust !)
-  protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
+  remote: 444 (no-rust !)
+  remote: 463 (rust !)
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (no-rust !)
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,persistent-nodemap,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash (rust !)
-  remote: 1 (sshv1 !)
+  remote: 1
   devel-peer-request: protocaps
   devel-peer-request:   caps: * bytes (glob)
   sending protocaps command
--- a/tests/test-wireproto-caching.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,468 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-persistent-nodemap is not enabled by default. It is not relevant for this test so disable it.
-
-  $ cat >> $HGRCPATH << EOF
-  > [format]
-  > use-persistent-nodemap = no
-  > [extensions]
-  > blackbox =
-  > [blackbox]
-  > track = simplecache
-  > EOF
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat >> .hg/hgrc << EOF
-  > [extensions]
-  > simplecache = $TESTDIR/wireprotosimplecache.py
-  > EOF
-
-  $ echo a0 > a
-  $ echo b0 > b
-  $ hg -q commit -A -m 'commit 0'
-  $ echo a1 > a
-  $ hg commit -m 'commit 1'
-  $ echo b1 > b
-  $ hg commit -m 'commit 2'
-  $ echo a2 > a
-  $ echo b2 > b
-  $ hg commit -m 'commit 3'
-
-  $ hg log -G -T '{rev}:{node} {desc}'
-  @  3:50590a86f3ff5d1e9a1624a7a6957884565cc8e8 commit 3
-  |
-  o  2:4d01eda50c6ac5f7e89cbe1880143a32f559c302 commit 2
-  |
-  o  1:4432d83626e8a98655f062ec1f2a43b07f7fbbb0 commit 1
-  |
-  o  0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
-  
-
-  $ hg --debug debugindex -m
-     rev linkrev nodeid                                   p1                                       p2
-       0       0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
-       1       1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
-       2       2 a8853dafacfca6fc807055a660d8b835141a3bb4 a988fb43583e871d1ed5750ee074c6d840bbbfc8 0000000000000000000000000000000000000000
-       3       3 3fe11dfbb13645782b0addafbe75a87c210ffddc a8853dafacfca6fc807055a660d8b835141a3bb4 0000000000000000000000000000000000000000
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Performing the same request should result in same result, with 2nd response
-coming from cache.
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-Sending different request doesn't yield cache hit.
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41', b'\xa9\x88\xfb\x43\x58\x3e\x87\x1d\x1e\xd5\x75\x0e\xe0\x74\xc6\xd8\x40\xbb\xbf\xc8']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'node': b'\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
-      b'parents': [
-        b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-  $ cat .hg/blackbox.log
-  *> cacher constructed for manifestdata (glob)
-  *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> cacher constructed for manifestdata (glob)
-  *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> cacher constructed for manifestdata (glob)
-  *> cache miss for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
-  *> storing cache entry for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
-
-  $ cat error.log
-
-  $ killdaemons.py
-  $ rm .hg/blackbox.log
-
-Try with object caching mode
-
-  $ cat >> .hg/hgrc << EOF
-  > [simplecache]
-  > cacheobjects = true
-  > EOF
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-  $ cat .hg/blackbox.log
-  *> cacher constructed for manifestdata (glob)
-  *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> cacher constructed for manifestdata (glob)
-  *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-
-  $ cat error.log
-
-  $ killdaemons.py
-  $ rm .hg/blackbox.log
-
-A non-cacheable command does not instantiate cacher
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-  $ sendhttpv2peer << EOF
-  > command capabilities
-  > EOF
-  creating http peer for wire protocol version 2
-  sending capabilities command
-  response: gen[
-    {
-      b'commands': {
-        b'branchmap': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'capabilities': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'changesetdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'bookmarks',
-                b'parents',
-                b'phase',
-                b'revision'
-              ])
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filedata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'path': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filesdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'dict'
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 50000
-        },
-        b'heads': {
-          b'args': {
-            b'publiconly': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'known': {
-          b'args': {
-            b'nodes': {
-              b'default': [],
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'listkeys': {
-          b'args': {
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'lookup': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'manifestdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'tree': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 100000
-        },
-        b'pushkey': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'new': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'old': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'push'
-          ]
-        },
-        b'rawstorefiledata': {
-          b'args': {
-            b'files': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        }
-      },
-      b'framingmediatypes': [
-        b'application/mercurial-exp-framing-0006'
-      ],
-      b'pathfilterprefixes': set([
-        b'path:',
-        b'rootfilesin:'
-      ]),
-      b'rawrepoformats': [
-        b'generaldelta',
-        b'revlogv1',
-        b'sparserevlog'
-      ]
-    }
-  ]
-
-  $ test -f .hg/blackbox.log
-  [1]
-
-An error is not cached
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa (esc)
-  [255]
-
-  $ cat .hg/blackbox.log
-  *> cacher constructed for manifestdata (glob)
-  *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob)
-  *> cacher exiting due to error (glob)
-
-  $ killdaemons.py
-  $ rm .hg/blackbox.log
--- a/tests/test-wireproto-command-branchmap.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ hg debugdrawdag << EOF
-  > C D
-  > |/
-  > B
-  > |
-  > A
-  > EOF
-
-  $ hg up B
-  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ hg branch branch1
-  marked working directory as branch branch1
-  (branches are permanent and global, did you want a bookmark?)
-  $ echo b1 > foo
-  $ hg -q commit -A -m 'branch 1'
-  $ hg up B
-  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
-  $ hg branch branch2
-  marked working directory as branch branch2
-  $ echo b2 > foo
-  $ hg -q commit -A -m 'branch 2'
-
-  $ hg log -T '{rev}:{node} {branch} {desc}\n'
-  5:224161c7589aa48fa83a48feff5e95b56ae327fc branch2 branch 2
-  4:b5faacdfd2633768cb3152336cc0953381266688 branch1 branch 1
-  3:be0ef73c17ade3fc89dc41701eb9fc3a91b58282 default D
-  2:26805aba1e600a82e93661149f2313866a221a7b default C
-  1:112478962961147124edd43549aedd1a335e44bf default B
-  0:426bada5c67598ca65036d57d9e4b64b0c1ce7a0 default A
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-No arguments returns something reasonable
-
-  $ sendhttpv2peer << EOF
-  > command branchmap
-  > EOF
-  creating http peer for wire protocol version 2
-  sending branchmap command
-  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-capabilities.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,762 +0,0 @@
-#require no-chg
-
-  $ . $TESTDIR/wireprotohelpers.sh
-
-persistent-nodemap is not enabled by default. It is not relevant for this test so disable it.
-
-  $ cat >> $HGRCPATH << EOF
-  > [format]
-  > use-persistent-nodemap = no
-  > EOF
-
-  $ hg init server
-
-zstd isn't present in plain builds. Make tests easier by removing
-zstd from the equation.
-
-  $ cat >> server/.hg/hgrc << EOF
-  > [server]
-  > compressionengines = zlib
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-A normal capabilities request is serviced for version 1
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 Script output follows\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-0.1\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-
-A proper request without the API server enabled returns the legacy response
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >    user-agent: test
-  >    x-hgupgrade-1: foo
-  >    x-hgproto-1: cbor
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: foo\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 Script output follows\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-0.1\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-
-Restart with just API server enabled. This enables serving the new format.
-
-  $ killdaemons.py
-  $ cat error.log
-
-  $ cat >> server/.hg/hgrc << EOF
-  > [experimental]
-  > web.apiserver = true
-  > EOF
-
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-X-HgUpgrade-<N> without CBOR advertisement uses legacy response
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >    user-agent: test
-  >    x-hgupgrade-1: foo bar
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     x-hgupgrade-1: foo bar\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 Script output follows\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-0.1\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-
-X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >    user-agent: test
-  >    x-hgupgrade-1: foo bar
-  >    x-hgproto-1: some value
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     x-hgproto-1: some value\r\n
-  s>     x-hgupgrade-1: foo bar\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 Script output follows\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-0.1\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-
-X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >    user-agent: test
-  >    x-hgupgrade-1: foo bar
-  >    x-hgproto-1: cbor
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: foo bar\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  cbor> [
-    {
-      b'apibase': b'api/',
-      b'apis': {},
-      b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
-    }
-  ]
-
-Restart server to enable HTTPv2
-
-  $ killdaemons.py
-  $ enablehttpv2 server
-  $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Only requested API services are returned
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >    user-agent: test
-  >    x-hgupgrade-1: foo bar
-  >    x-hgproto-1: cbor
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: foo bar\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  cbor> [
-    {
-      b'apibase': b'api/',
-      b'apis': {},
-      b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
-    }
-  ]
-
-Request for HTTPv2 service returns information about it
-
-  $ sendhttpraw << EOF
-  > httprequest GET ?cmd=capabilities
-  >    user-agent: test
-  >    x-hgupgrade-1: exp-http-v2-0003 foo bar
-  >    x-hgproto-1: cbor
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003 foo bar\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogNv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  cbor> [
-    {
-      b'apibase': b'api/',
-      b'apis': {
-        b'exp-http-v2-0003': {
-          b'commands': {
-            b'branchmap': {
-              b'args': {},
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'capabilities': {
-              b'args': {},
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'changesetdata': {
-              b'args': {
-                b'fields': {
-                  b'default': set([]),
-                  b'required': False,
-                  b'type': b'set',
-                  b'validvalues': set([
-                    b'bookmarks',
-                    b'parents',
-                    b'phase',
-                    b'revision'
-                  ])
-                },
-                b'revisions': {
-                  b'required': True,
-                  b'type': b'list'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'filedata': {
-              b'args': {
-                b'fields': {
-                  b'default': set([]),
-                  b'required': False,
-                  b'type': b'set',
-                  b'validvalues': set([
-                    b'linknode',
-                    b'parents',
-                    b'revision'
-                  ])
-                },
-                b'haveparents': {
-                  b'default': False,
-                  b'required': False,
-                  b'type': b'bool'
-                },
-                b'nodes': {
-                  b'required': True,
-                  b'type': b'list'
-                },
-                b'path': {
-                  b'required': True,
-                  b'type': b'bytes'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'filesdata': {
-              b'args': {
-                b'fields': {
-                  b'default': set([]),
-                  b'required': False,
-                  b'type': b'set',
-                  b'validvalues': set([
-                    b'firstchangeset',
-                    b'linknode',
-                    b'parents',
-                    b'revision'
-                  ])
-                },
-                b'haveparents': {
-                  b'default': False,
-                  b'required': False,
-                  b'type': b'bool'
-                },
-                b'pathfilter': {
-                  b'default': None,
-                  b'required': False,
-                  b'type': b'dict'
-                },
-                b'revisions': {
-                  b'required': True,
-                  b'type': b'list'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ],
-              b'recommendedbatchsize': 50000
-            },
-            b'heads': {
-              b'args': {
-                b'publiconly': {
-                  b'default': False,
-                  b'required': False,
-                  b'type': b'bool'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'known': {
-              b'args': {
-                b'nodes': {
-                  b'default': [],
-                  b'required': False,
-                  b'type': b'list'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'listkeys': {
-              b'args': {
-                b'namespace': {
-                  b'required': True,
-                  b'type': b'bytes'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'lookup': {
-              b'args': {
-                b'key': {
-                  b'required': True,
-                  b'type': b'bytes'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            },
-            b'manifestdata': {
-              b'args': {
-                b'fields': {
-                  b'default': set([]),
-                  b'required': False,
-                  b'type': b'set',
-                  b'validvalues': set([
-                    b'parents',
-                    b'revision'
-                  ])
-                },
-                b'haveparents': {
-                  b'default': False,
-                  b'required': False,
-                  b'type': b'bool'
-                },
-                b'nodes': {
-                  b'required': True,
-                  b'type': b'list'
-                },
-                b'tree': {
-                  b'required': True,
-                  b'type': b'bytes'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ],
-              b'recommendedbatchsize': 100000
-            },
-            b'pushkey': {
-              b'args': {
-                b'key': {
-                  b'required': True,
-                  b'type': b'bytes'
-                },
-                b'namespace': {
-                  b'required': True,
-                  b'type': b'bytes'
-                },
-                b'new': {
-                  b'required': True,
-                  b'type': b'bytes'
-                },
-                b'old': {
-                  b'required': True,
-                  b'type': b'bytes'
-                }
-              },
-              b'permissions': [
-                b'push'
-              ]
-            },
-            b'rawstorefiledata': {
-              b'args': {
-                b'files': {
-                  b'required': True,
-                  b'type': b'list'
-                },
-                b'pathfilter': {
-                  b'default': None,
-                  b'required': False,
-                  b'type': b'list'
-                }
-              },
-              b'permissions': [
-                b'pull'
-              ]
-            }
-          },
-          b'framingmediatypes': [
-            b'application/mercurial-exp-framing-0006'
-          ],
-          b'pathfilterprefixes': set([
-            b'path:',
-            b'rootfilesin:'
-          ]),
-          b'rawrepoformats': [
-            b'generaldelta',
-            b'revlogv1',
-            b'sparserevlog'
-          ]
-        }
-      },
-      b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
-    }
-  ]
-
-capabilities command returns expected info
-
-  $ sendhttpv2peerhandshake << EOF
-  > command capabilities
-  > EOF
-  creating http peer for wire protocol version 2
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: *\r\n (glob)
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogNv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  sending capabilities command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 63\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity\x13\x00\x00\x01\x00\x01\x00\x11\xa1DnameLcapabilities
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     65e\r\n
-  s>     V\x06\x00\x01\x00\x02\x041
-  s>     \xa4Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1Lsparserevlog
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: gen[
-    {
-      b'commands': {
-        b'branchmap': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'capabilities': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'changesetdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'bookmarks',
-                b'parents',
-                b'phase',
-                b'revision'
-              ])
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filedata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'path': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filesdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'dict'
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 50000
-        },
-        b'heads': {
-          b'args': {
-            b'publiconly': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'known': {
-          b'args': {
-            b'nodes': {
-              b'default': [],
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'listkeys': {
-          b'args': {
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'lookup': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'manifestdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'tree': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 100000
-        },
-        b'pushkey': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'new': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'old': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'push'
-          ]
-        },
-        b'rawstorefiledata': {
-          b'args': {
-            b'files': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        }
-      },
-      b'framingmediatypes': [
-        b'application/mercurial-exp-framing-0006'
-      ],
-      b'pathfilterprefixes': set([
-        b'path:',
-        b'rootfilesin:'
-      ]),
-      b'rawrepoformats': [
-        b'generaldelta',
-        b'revlogv1',
-        b'sparserevlog'
-      ]
-    }
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat error.log
--- a/tests/test-wireproto-command-changesetdata.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,613 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat >> .hg/hgrc << EOF
-  > [phases]
-  > publish = false
-  > EOF
-  $ echo a0 > a
-  $ echo b0 > b
-
-  $ hg -q commit -A -m 'commit 0'
-
-  $ echo a1 > a
-  $ echo b1 > b
-  $ hg commit -m 'commit 1'
-  $ echo b2 > b
-  $ hg commit -m 'commit 2'
-  $ hg phase --public -r .
-
-  $ hg -q up -r 0
-  $ echo a2 > a
-  $ hg commit -m 'commit 3'
-  created new head
-
-  $ hg log -G -T '{rev}:{node} {desc}\n'
-  @  3:eae5f82c2e622368d27daecb76b7e393d0f24211 commit 3
-  |
-  | o  2:0bb8ad894a15b15380b2a2a5b183e20f2a4b28dd commit 2
-  | |
-  | o  1:7592917e1c3e82677cb0a4bc715ca25dd12d28c1 commit 1
-  |/
-  o  0:3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
-  
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-No arguments is an invalid request
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: missing required arguments: revisions
-  [255]
-
-Missing nodes for changesetexplicit results in error
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetexplicit'}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: nodes key not present in changesetexplicit revision specifier
-  [255]
-
-changesetexplicitdepth requires nodes and depth keys
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetexplicitdepth'}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: nodes key not present in changesetexplicitdepth revision specifier
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetexplicitdepth', b'nodes': []}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: depth key not present in changesetexplicitdepth revision specifier
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetexplicitdepth', b'depth': 42}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: nodes key not present in changesetexplicitdepth revision specifier
-  [255]
-
-changesetdagrange requires roots and heads keys
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetdagrange'}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: roots key not present in changesetdagrange revision specifier
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetdagrange', b'roots': []}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: heads key not present in changesetdagrange revision specifier
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetdagrange', b'heads': [b'dummy']}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: roots key not present in changesetdagrange revision specifier
-  [255]
-
-Empty changesetdagrange heads results in an error
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{b'type': b'changesetdagrange', b'heads': [], b'roots': []}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  abort: heads key in changesetdagrange cannot be empty
-  [255]
-
-Sending just dagrange heads sends all revisions
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{
-  >         b'type': b'changesetdagrange',
-  >         b'roots': [],
-  >         b'heads': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 4
-    },
-    {
-      b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:'
-    },
-    {
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1'
-    },
-    {
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-Sending root nodes limits what data is sent
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{
-  >         b'type': b'changesetdagrange',
-  >         b'roots': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'],
-  >         b'heads': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1'
-    },
-    {
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    }
-  ]
-
-Requesting data on a single node by node works
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a']}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:'
-    }
-  ]
-
-Specifying a noderange and nodes takes union
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[
-  >         {
-  >             b'type': b'changesetexplicit',
-  >             b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
-  >         },
-  >         {
-  >             b'type': b'changesetdagrange',
-  >             b'roots': [b'\x75\x92\x91\x7e\x1c\x3e\x82\x67\x7c\xb0\xa4\xbc\x71\x5c\xa2\x5d\xd1\x2d\x28\xc1'],
-  >             b'heads': [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd'],
-  >         }]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    },
-    {
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    }
-  ]
-
-nodesdepth of 1 limits to exactly requested nodes
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicitdepth',
-  >         b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
-  >         b'depth': 1}] 
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-nodesdepth of 2 limits to first ancestor
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicitdepth',
-  >         b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
-  >         b'depth': 2}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:'
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-nodesdepth with multiple nodes
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicitdepth',
-  >         b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd'],
-  >         b'depth': 2}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 4
-    },
-    {
-      b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:'
-    },
-    {
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1'
-    },
-    {
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-Parents data is transferred upon request
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'parents']
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11',
-      b'parents': [
-        b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-Phase data is transferred upon request
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'phase']
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd',
-      b'phase': b'public'
-    }
-  ]
-
-Revision data is transferred upon request
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'revision']
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          61
-        ]
-      ],
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    },
-    b'1b74476799ec8318045db759b1b4bcc9b839d0aa\ntest\n0 0\na\n\ncommit 3'
-  ]
-
-Bookmarks key isn't present if no bookmarks data
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'bookmarks']
-  >     revisions eval:[{
-  >         b'type': b'changesetdagrange',
-  >         b'roots': [],
-  >         b'heads': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 4
-    },
-    {
-      b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:'
-    },
-    {
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1'
-    },
-    {
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    },
-    {
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-Bookmarks are sent when requested
-
-  $ hg -R ../server bookmark -r 0bb8ad894a15b15380b2a2a5b183e20f2a4b28dd book-1
-  $ hg -R ../server bookmark -r eae5f82c2e622368d27daecb76b7e393d0f24211 book-2
-  $ hg -R ../server bookmark -r eae5f82c2e622368d27daecb76b7e393d0f24211 book-3
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'bookmarks']
-  >     revisions eval:[{
-  >         b'type': b'changesetdagrange',
-  >         b'roots': [],
-  >         b'heads': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 4
-    },
-    {
-      b'node': b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:'
-    },
-    {
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1'
-    },
-    {
-      b'bookmarks': [
-        b'book-1'
-      ],
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    },
-    {
-      b'bookmarks': [
-        b'book-2',
-        b'book-3'
-      ],
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-Bookmarks are sent when we make a no-new-revisions request
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'bookmarks', b'revision']
-  >     revisions eval:[{
-  >         b'type': b'changesetdagrange',
-  >         b'roots': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
-  >         b'heads': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          63
-        ]
-      ],
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1'
-    },
-    b'7f144aea0ba742713887b564d57e9d12f12ff382\ntest\n0 0\na\nb\n\ncommit 1',
-    {
-      b'bookmarks': [
-        b'book-1'
-      ],
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          61
-        ]
-      ],
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd'
-    },
-    b'37f0a2d1c28ffe4b879109a7d1bbf8f07b3c763b\ntest\n0 0\nb\n\ncommit 2',
-    {
-      b'bookmarks': [
-        b'book-2',
-        b'book-3'
-      ],
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11'
-    }
-  ]
-
-Multiple fields can be transferred
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'parents', b'revision']
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          61
-        ]
-      ],
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11',
-      b'parents': [
-        b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    b'1b74476799ec8318045db759b1b4bcc9b839d0aa\ntest\n0 0\na\n\ncommit 3'
-  ]
-
-Base nodes have just their metadata (e.g. phase) transferred
-TODO this doesn't work
-
-  $ sendhttpv2peer << EOF
-  > command changesetdata
-  >     fields eval:[b'phase', b'parents', b'revision']
-  >     revisions eval:[{
-  >         b'type': b'changesetdagrange',
-  >         b'roots': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'],
-  >         b'heads': [
-  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
-  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending changesetdata command
-  response: gen[
-    {
-      b'totalitems': 3
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          63
-        ]
-      ],
-      b'node': b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1',
-      b'parents': [
-        b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ],
-      b'phase': b'public'
-    },
-    b'7f144aea0ba742713887b564d57e9d12f12ff382\ntest\n0 0\na\nb\n\ncommit 1',
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          61
-        ]
-      ],
-      b'node': b'\x0b\xb8\xad\x89J\x15\xb1S\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f*K(\xdd',
-      b'parents': [
-        b'u\x92\x91~\x1c>\x82g|\xb0\xa4\xbcq\\\xa2]\xd1-(\xc1',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ],
-      b'phase': b'public'
-    },
-    b'37f0a2d1c28ffe4b879109a7d1bbf8f07b3c763b\ntest\n0 0\nb\n\ncommit 2',
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          61
-        ]
-      ],
-      b'node': b'\xea\xe5\xf8,.b#h\xd2}\xae\xcbv\xb7\xe3\x93\xd0\xf2B\x11',
-      b'parents': [
-        b'3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ],
-      b'phase': b'draft'
-    },
-    b'1b74476799ec8318045db759b1b4bcc9b839d0aa\ntest\n0 0\na\n\ncommit 3'
-  ]
-
-  $ cat error.log
--- a/tests/test-wireproto-command-filedata.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,364 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat > a << EOF
-  > a0
-  > 00000000000000000000000000000000000000
-  > 11111111111111111111111111111111111111
-  > EOF
-  $ echo b0 > b
-  $ mkdir -p dir0/child0 dir0/child1 dir1
-  $ echo c0 > dir0/c
-  $ echo d0 > dir0/d
-  $ echo e0 > dir0/child0/e
-  $ echo f0 > dir0/child1/f
-  $ hg -q commit -A -m 'commit 0'
-
-  $ echo a1 >> a
-  $ echo d1 > dir0/d
-  $ hg commit -m 'commit 1'
-  $ echo f1 > dir0/child1/f
-  $ hg commit -m 'commit 2'
-
-  $ hg -q up -r 0
-  $ echo a2 >> a
-  $ hg commit -m 'commit 3'
-  created new head
-
-Create multiple heads introducing the same changeset
-
-  $ hg -q up -r 0
-  $ echo foo > dupe-file
-  $ hg commit -Am 'dupe 1'
-  adding dupe-file
-  created new head
-  $ hg -q up -r 0
-  $ echo foo > dupe-file
-  $ hg commit -Am 'dupe 2'
-  adding dupe-file
-  created new head
-
-  $ hg log -G -T '{rev}:{node} {desc}\n'
-  @  5:732c3dd7bee94242de656000e5f458e7ccfe2828 dupe 2
-  |
-  | o  4:4334f10897d13c3e8beb4b636f7272b4ec2d0322 dupe 1
-  |/
-  | o  3:5ce944d7fece1252dae06c34422b573c191b9489 commit 3
-  |/
-  | o  2:b3c27db01410dae01e5485d425b1440078df540c commit 2
-  | |
-  | o  1:3ef5e551f219ba505481d34d6b0316b017fa3f00 commit 1
-  |/
-  o  0:91b232a2253ce0638496f67bdfd7a4933fb51b25 commit 0
-  
-
-  $ hg --debug debugindex a
-     rev linkrev nodeid                                   p1                                       p2
-       0       0 649d149df43d83882523b7fb1e6a3af6f1907b39 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
-       1       1 0a86321f1379d1a9ecd0579a22977af7a5acaf11 649d149df43d83882523b7fb1e6a3af6f1907b39 0000000000000000000000000000000000000000
-       2       3 7e5801b6d5f03a5a54f3c47b583f7567aad43e5b 649d149df43d83882523b7fb1e6a3af6f1907b39 0000000000000000000000000000000000000000
-
-  $ hg --debug debugindex dir0/child0/e
-     rev linkrev nodeid                                   p1                                       p2
-       0       0 bbba6c06b30f443d34ff841bc985c4d0827c6be4 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
-
-  $ hg --debug debugindex dupe-file
-     rev linkrev nodeid                                   p1                                       p2
-       0       4 2ed2a3912a0b24502043eae84ee4b279c18b90dd 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Missing arguments is an error
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  abort: missing required arguments: nodes, path
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  abort: missing required arguments: path
-  [255]
-
-Unknown node is an error
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
-  >     path eval:b'a'
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  abort: unknown file node: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-  [255]
-
-Fetching a single revision returns just metadata by default
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11']
-  >     path eval:b'a'
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    }
-  ]
-
-Requesting parents works
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11']
-  >     path eval:b'a'
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11',
-      b'parents': [
-        b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-Requesting revision data works
-(haveparents defaults to False, so fulltext is emitted)
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11']
-  >     path eval:b'a'
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          84
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n'
-  ]
-
-haveparents=False should be same as above
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11']
-  >     path eval:b'a'
-  >     fields eval:[b'revision']
-  >     haveparents eval:False
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          84
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n'
-  ]
-
-haveparents=True should emit a delta
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11']
-  >     path eval:b'a'
-  >     fields eval:[b'revision']
-  >     haveparents eval:True
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n'
-  ]
-
-Requesting multiple revisions works
-(first revision is a fulltext since haveparents=False by default)
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x64\x9d\x14\x9d\xf4\x3d\x83\x88\x25\x23\xb7\xfb\x1e\x6a\x3a\xf6\xf1\x90\x7b\x39', b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11']
-  >     path eval:b'a'
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          81
-        ]
-      ],
-      b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
-    {
-      b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n'
-  ]
-
-Revisions are sorted by DAG order, parents first
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x0a\x86\x32\x1f\x13\x79\xd1\xa9\xec\xd0\x57\x9a\x22\x97\x7a\xf7\xa5\xac\xaf\x11', b'\x64\x9d\x14\x9d\xf4\x3d\x83\x88\x25\x23\xb7\xfb\x1e\x6a\x3a\xf6\xf1\x90\x7b\x39']
-  >     path eval:b'a'
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          81
-        ]
-      ],
-      b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
-    {
-      b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n'
-  ]
-
-Requesting parents and revision data works
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x7e\x58\x01\xb6\xd5\xf0\x3a\x5a\x54\xf3\xc4\x7b\x58\x3f\x75\x67\xaa\xd4\x3e\x5b']
-  >     path eval:b'a'
-  >     fields eval:[b'parents', b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          84
-        ]
-      ],
-      b'node': b'~X\x01\xb6\xd5\xf0:ZT\xf3\xc4{X?ug\xaa\xd4>[',
-      b'parents': [
-        b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na2\n'
-  ]
-
-Linknode for duplicate revision is the initial revision
-
-  $ sendhttpv2peer << EOF
-  > command filedata
-  >     nodes eval:[b'\x2e\xd2\xa3\x91\x2a\x0b\x24\x50\x20\x43\xea\xe8\x4e\xe4\xb2\x79\xc1\x8b\x90\xdd']
-  >     path eval:b'dupe-file'
-  >     fields eval:[b'linknode', b'parents', b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filedata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          4
-        ]
-      ],
-      b'linknode': b'C4\xf1\x08\x97\xd1<>\x8b\xebKcorr\xb4\xec-\x03"',
-      b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    b'foo\n'
-  ]
-
-  $ cat error.log
--- a/tests/test-wireproto-command-filesdata.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1298 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat > a << EOF
-  > a0
-  > 00000000000000000000000000000000000000
-  > 11111111111111111111111111111111111111
-  > EOF
-  $ cat > b << EOF
-  > b0
-  > aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-  > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-  > EOF
-  $ mkdir -p dir0/child0 dir0/child1 dir1
-  $ echo c0 > dir0/c
-  $ echo d0 > dir0/d
-  $ echo e0 > dir0/child0/e
-  $ echo f0 > dir0/child1/f
-  $ hg -q commit -A -m 'commit 0'
-
-  $ echo a1 >> a
-  $ echo d1 > dir0/d
-  $ echo g0 > g
-  $ echo h0 > h
-  $ hg -q commit -A -m 'commit 1'
-  $ echo f1 > dir0/child1/f
-  $ echo i0 > dir0/i
-  $ hg -q commit -A -m 'commit 2'
-
-  $ hg -q up -r 0
-  $ echo a2 >> a
-  $ hg commit -m 'commit 3'
-  created new head
-
-Create multiple heads introducing the same file nodefile node
-
-  $ hg -q up -r 0
-  $ echo foo > dupe-file
-  $ hg commit -Am 'dupe 1'
-  adding dupe-file
-  created new head
-  $ hg -q up -r 0
-  $ echo foo > dupe-file
-  $ hg commit -Am 'dupe 2'
-  adding dupe-file
-  created new head
-
-  $ hg log -G -T '{rev}:{node} {desc}\n'
-  @  5:47fc30580911232cb264675b402819deddf6c6f0 dupe 2
-  |
-  | o  4:b16cce2967c1749ef4f4e3086a806cfbad8a3af7 dupe 1
-  |/
-  | o  3:476fbf122cd82f6726f0191ff146f67140946abc commit 3
-  |/
-  | o  2:b91c03cbba3519ab149b6cd0a0afbdb5cf1b5c8a commit 2
-  | |
-  | o  1:5b0b1a23577e205ea240e39c9704e28d7697cbd8 commit 1
-  |/
-  o  0:6e875ff18c227659ad6143bb3580c65700734884 commit 0
-  
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Missing arguments is an error
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  abort: missing required arguments: revisions
-  [255]
-
-Bad pattern to pathfilter is rejected
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >          b'type': b'changesetexplicit',
-  >          b'nodes': [
-  >              b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >          ]}]
-  >     pathfilter eval:{b'include': [b'bad:foo']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  abort: include pattern must begin with `path:` or `rootfilesin:`; got bad:foo
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     pathfilter eval:{b'exclude': [b'glob:foo']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  abort: exclude pattern must begin with `path:` or `rootfilesin:`; got glob:foo
-  [255]
-
-Fetching a single changeset without parents fetches all files
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 8,
-      b'totalpaths': 8
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
-    },
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
-    },
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
-    },
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    }
-  ]
-
-Fetching a single changeset saying parents data is available fetches just new files
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     haveparents eval:True
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 4,
-      b'totalpaths': 4
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    }
-  ]
-
-A path filter for a sub-directory is honored
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     haveparents eval:True
-  >     pathfilter eval:{b'include': [b'path:dir0']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 1,
-      b'totalpaths': 1
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    }
-  ]
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     haveparents eval:True
-  >     pathfilter eval:{b'exclude': [b'path:a', b'path:g']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 2,
-      b'totalpaths': 2
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    }
-  ]
-
-Requesting multiple changeset nodes without haveparents sends all data for both
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >             b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
-  >         ]}]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 10,
-      b'totalpaths': 9
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
-    },
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
-    },
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
-    },
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 2
-    },
-    {
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
-    },
-    {
-      b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    {
-      b'path': b'dir0/i',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
-    },
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    }
-  ]
-
-Requesting multiple changeset nodes with haveparents sends incremental data for both
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >             b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
-  >         ]}]
-  >     haveparents eval:True
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 6,
-      b'totalpaths': 6
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    {
-      b'path': b'dir0/i',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
-    },
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    }
-  ]
-
-Requesting parents works
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 8,
-      b'totalpaths': 8
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11',
-      b'parents': [
-        b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G',
-      b'parents': [
-        b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-Requesting revision data works
-(haveparents defaults to False, so fulltext is emitted)
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 8,
-      b'totalpaths': 8
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          84
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          81
-        ]
-      ],
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
-    },
-    b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
-    },
-    b'c0\n',
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
-    },
-    b'e0\n',
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
-    },
-    b'f0\n',
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    b'd1\n',
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    b'g0\n',
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    },
-    b'h0\n'
-  ]
-
-haveparents=False should be same as above
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     fields eval:[b'revision']
-  >     haveparents eval:False
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 8,
-      b'totalpaths': 8
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          84
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\na1\n',
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          81
-        ]
-      ],
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
-    },
-    b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
-    },
-    b'c0\n',
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
-    },
-    b'e0\n',
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
-    },
-    b'f0\n',
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    b'd1\n',
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    b'g0\n',
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    },
-    b'h0\n'
-  ]
-
-haveparents=True should emit a delta
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >         ]}]
-  >     fields eval:[b'revision']
-  >     haveparents eval:True
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 4,
-      b'totalpaths': 4
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 1
-    },
-    {
-      b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 1
-    },
-    {
-      b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    b'g0\n',
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    },
-    b'h0\n'
-  ]
-
-Requesting multiple revisions works
-(first revision is a fulltext since haveparents=False by default)
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >             b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
-  >         ]}]
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 12,
-      b'totalpaths': 9
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          81
-        ]
-      ],
-      b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
-    },
-    b'a0\n00000000000000000000000000000000000000\n11111111111111111111111111111111111111\n',
-    {
-      b'deltabasenode': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    b'\x00\x00\x00Q\x00\x00\x00Q\x00\x00\x00\x03a1\n',
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          81
-        ]
-      ],
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
-    },
-    b'b0\naaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n',
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
-    },
-    b'c0\n',
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
-    },
-    b'e0\n',
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
-    },
-    b'f0\n',
-    {
-      b'deltabasenode': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03f1\n',
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
-    },
-    b'd0\n',
-    {
-      b'deltabasenode': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          15
-        ]
-      ],
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03d1\n',
-    {
-      b'path': b'dir0/i',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
-    },
-    b'i0\n',
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    b'g0\n',
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          3
-        ]
-      ],
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    },
-    b'h0\n'
-  ]
-
-Requesting linknode field works
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x6e\x87\x5f\xf1\x8c\x22\x76\x59\xad\x61\x43\xbb\x35\x80\xc6\x57\x00\x73\x48\x84',
-  >             b'\x5b\x0b\x1a\x23\x57\x7e\x20\x5e\xa2\x40\xe3\x9c\x97\x04\xe2\x8d\x76\x97\xcb\xd8',
-  >             b'\xb9\x1c\x03\xcb\xba\x35\x19\xab\x14\x9b\x6c\xd0\xa0\xaf\xbd\xb5\xcf\x1b\x5c\x8a',
-  >         ]}]
-  >     fields eval:[b'linknode']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 12,
-      b'totalpaths': 9
-    },
-    {
-      b'path': b'a',
-      b'totalitems': 2
-    },
-    {
-      b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
-      b'node': b'd\x9d\x14\x9d\xf4=\x83\x88%#\xb7\xfb\x1ej:\xf6\xf1\x90{9'
-    },
-    {
-      b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
-      b'node': b'\n\x862\x1f\x13y\xd1\xa9\xec\xd0W\x9a"\x97z\xf7\xa5\xac\xaf\x11'
-    },
-    {
-      b'path': b'b',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
-      b'node': b'\x88\xbac\xb8\xd8\xc6 :\xc6z\xc9\x98\xac\xd9\x17K\xf7\x05!\xb2'
-    },
-    {
-      b'path': b'dir0/c',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
-      b'node': b'\x91DE4j\x0c\xa0b\x9b\xd4|\xeb]\xfe\x07\xe4\xd4\xcf%\x01'
-    },
-    {
-      b'path': b'dir0/child0/e',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
-      b'node': b'\xbb\xbal\x06\xb3\x0fD=4\xff\x84\x1b\xc9\x85\xc4\xd0\x82|k\xe4'
-    },
-    {
-      b'path': b'dir0/child1/f',
-      b'totalitems': 2
-    },
-    {
-      b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
-      b'node': b'\x12\xfc}\xcdw;Z\n\x92\x9c\xe1\x95"\x80\x83\xc6\xdd\xc9\xce\xc4'
-    },
-    {
-      b'linknode': b'\xb9\x1c\x03\xcb\xba5\x19\xab\x14\x9bl\xd0\xa0\xaf\xbd\xb5\xcf\x1b\\\x8a',
-      b'node': b'(\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e'
-    },
-    {
-      b'path': b'dir0/d',
-      b'totalitems': 2
-    },
-    {
-      b'linknode': b'n\x87_\xf1\x8c"vY\xadaC\xbb5\x80\xc6W\x00sH\x84',
-      b'node': b'S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4&'
-    },
-    {
-      b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
-      b'node': b'\x93\x88)\xad\x01R}2\xba\x06_\x81#6\xfe\xc7\x9d\xdd9G'
-    },
-    {
-      b'path': b'dir0/i',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'\xb9\x1c\x03\xcb\xba5\x19\xab\x14\x9bl\xd0\xa0\xaf\xbd\xb5\xcf\x1b\\\x8a',
-      b'node': b'\xd7t\xb5\x80Jq\xfd1\xe1\xae\x05\xea\x8e2\xdd\x9b\xa3\xd8S\xd7'
-    },
-    {
-      b'path': b'g',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
-      b'node': b'\xde\xca\xba5DFjI\x95r\xe9\x0f\xac\xe6\xfa\x0c!k\xba\x8c'
-    },
-    {
-      b'path': b'h',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'[\x0b\x1a#W~ ^\xa2@\xe3\x9c\x97\x04\xe2\x8dv\x97\xcb\xd8',
-      b'node': b'\x03A\xfc\x84\x1b\xb5\xb4\xba\x93\xb2mM\xdaa\xf7y6]\xb3K'
-    }
-  ]
-
-Test behavior where a file node is introduced in 2 DAG heads
-
-Request for changeset introducing filenode returns linknode as self
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\xb1\x6c\xce\x29\x67\xc1\x74\x9e\xf4\xf4\xe3\x08\x6a\x80\x6c\xfb\xad\x8a\x3a\xf7',
-  >         ]}]
-  >     fields eval:[b'linknode']
-  >     pathfilter eval:{b'include': [b'path:dupe-file']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 1,
-      b'totalpaths': 1
-    },
-    {
-      b'path': b'dupe-file',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'\xb1l\xce)g\xc1t\x9e\xf4\xf4\xe3\x08j\x80l\xfb\xad\x8a:\xf7',
-      b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd'
-    }
-  ]
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\xb1\x6c\xce\x29\x67\xc1\x74\x9e\xf4\xf4\xe3\x08\x6a\x80\x6c\xfb\xad\x8a\x3a\xf7',
-  >         ]}]
-  >     fields eval:[b'linknode']
-  >     haveparents eval:True
-  >     pathfilter eval:{b'include': [b'path:dupe-file']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 1,
-      b'totalpaths': 1
-    },
-    {
-      b'path': b'dupe-file',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'\xb1l\xce)g\xc1t\x9e\xf4\xf4\xe3\x08j\x80l\xfb\xad\x8a:\xf7',
-      b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd'
-    }
-  ]
-
-Request for changeset where recorded linknode isn't in DAG ancestry will get
-rewritten accordingly
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x47\xfc\x30\x58\x09\x11\x23\x2c\xb2\x64\x67\x5b\x40\x28\x19\xde\xdd\xf6\xc6\xf0',
-  >         ]}]
-  >     fields eval:[b'linknode']
-  >     pathfilter eval:{b'include': [b'path:dupe-file']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 1,
-      b'totalpaths': 1
-    },
-    {
-      b'path': b'dupe-file',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'G\xfc0X\t\x11#,\xb2dg[@(\x19\xde\xdd\xf6\xc6\xf0',
-      b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd'
-    }
-  ]
-
-  $ sendhttpv2peer << EOF
-  > command filesdata
-  >     revisions eval:[{
-  >         b'type': b'changesetexplicit',
-  >         b'nodes': [
-  >             b'\x47\xfc\x30\x58\x09\x11\x23\x2c\xb2\x64\x67\x5b\x40\x28\x19\xde\xdd\xf6\xc6\xf0',
-  >         ]}]
-  >     fields eval:[b'linknode']
-  >     haveparents eval:True
-  >     pathfilter eval:{b'include': [b'path:dupe-file']}
-  > EOF
-  creating http peer for wire protocol version 2
-  sending filesdata command
-  response: gen[
-    {
-      b'totalitems': 1,
-      b'totalpaths': 1
-    },
-    {
-      b'path': b'dupe-file',
-      b'totalitems': 1
-    },
-    {
-      b'linknode': b'G\xfc0X\t\x11#,\xb2dg[@(\x19\xde\xdd\xf6\xc6\xf0',
-      b'node': b'.\xd2\xa3\x91*\x0b$P C\xea\xe8N\xe4\xb2y\xc1\x8b\x90\xdd'
-    }
-  ]
-
-  $ cat error.log
--- a/tests/test-wireproto-command-heads.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ hg debugdrawdag << EOF
-  > H I J
-  > | | |
-  > E F G
-  > | |/
-  > C D
-  > |/
-  > B
-  > |
-  > A
-  > EOF
-
-  $ hg phase --force --secret J
-  $ hg phase --public E
-
-  $ hg log -r 'E + H + I + G + J' -T '{rev}:{node} {desc} {phase}\n'
-  4:78d2dca436b2f5b188ac267e29b81e07266d38fc E public
-  7:ae492e36b0c8339ffaf328d00b85b4525de1165e H draft
-  8:1d6f6b91d44aaba6d5e580bc30a9948530dbe00b I draft
-  6:29446d2dc5419c5f97447a8bc062e4cc328bf241 G draft
-  9:dec04b246d7cbb670c6689806c05ad17c835284e J secret
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-All non-secret heads returned by default
-
-  $ sendhttpv2peer << EOF
-  > command heads
-  > EOF
-  creating http peer for wire protocol version 2
-  sending heads command
-  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
-
-  $ sendhttpv2peer << EOF
-  > command heads
-  >     publiconly 1
-  > EOF
-  creating http peer for wire protocol version 2
-  sending heads command
-  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	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ hg debugdrawdag << EOF
-  > C D
-  > |/
-  > B
-  > |
-  > A
-  > EOF
-
-  $ hg log -T '{rev}:{node} {desc}\n'
-  3:be0ef73c17ade3fc89dc41701eb9fc3a91b58282 D
-  2:26805aba1e600a82e93661149f2313866a221a7b C
-  1:112478962961147124edd43549aedd1a335e44bf B
-  0:426bada5c67598ca65036d57d9e4b64b0c1ce7a0 A
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-No arguments returns something reasonable
-
-  $ sendhttpv2peer << EOF
-  > command known
-  > EOF
-  creating http peer for wire protocol version 2
-  sending known command
-  response: []
-
-Single known node works
-
-  $ sendhttpv2peer << EOF
-  > command known
-  >     nodes eval:[b'\x42\x6b\xad\xa5\xc6\x75\x98\xca\x65\x03\x6d\x57\xd9\xe4\xb6\x4b\x0c\x1c\xe7\xa0']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending known command
-  response: [
-    True
-  ]
-
-Multiple nodes works
-
-  $ sendhttpv2peer << EOF
-  > command known
-  >     nodes eval:[b'\x42\x6b\xad\xa5\xc6\x75\x98\xca\x65\x03\x6d\x57\xd9\xe4\xb6\x4b\x0c\x1c\xe7\xa0', b'00000000000000000000', b'\x11\x24\x78\x96\x29\x61\x14\x71\x24\xed\xd4\x35\x49\xae\xdd\x1a\x33\x5e\x44\xbf']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending known command
-  response: [
-    True,
-    False,
-    True
-  ]
-
-  $ cat error.log
--- a/tests/test-wireproto-command-listkeys.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ hg debugdrawdag << EOF
-  > C D
-  > |/
-  > B
-  > |
-  > A
-  > EOF
-
-  $ hg phase --public -r C
-  $ hg book -r C @
-
-  $ hg log -T '{rev}:{node} {desc}\n'
-  3:be0ef73c17ade3fc89dc41701eb9fc3a91b58282 D
-  2:26805aba1e600a82e93661149f2313866a221a7b C
-  1:112478962961147124edd43549aedd1a335e44bf B
-  0:426bada5c67598ca65036d57d9e4b64b0c1ce7a0 A
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Request for namespaces works
-
-  $ sendhttpv2peer << EOF
-  > command listkeys
-  >     namespace namespaces
-  > EOF
-  creating http peer for wire protocol version 2
-  sending listkeys command
-  response: {
-    b'bookmarks': b'',
-    b'namespaces': b'',
-    b'phases': b''
-  }
-
-Request for phases works
-
-  $ sendhttpv2peer << EOF
-  > command listkeys
-  >     namespace phases
-  > EOF
-  creating http peer for wire protocol version 2
-  sending listkeys command
-  response: {
-    b'be0ef73c17ade3fc89dc41701eb9fc3a91b58282': b'1',
-    b'publishing': b'True'
-  }
-
-Request for bookmarks works
-
-  $ sendhttpv2peer << EOF
-  > command listkeys
-  >     namespace bookmarks
-  > EOF
-  creating http peer for wire protocol version 2
-  sending listkeys command
-  response: {
-    b'@': b'26805aba1e600a82e93661149f2313866a221a7b'
-  }
-
-  $ cat error.log
--- a/tests/test-wireproto-command-lookup.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat >> .hg/hgrc << EOF
-  > [web]
-  > push_ssl = false
-  > allow-push = *
-  > EOF
-  $ hg debugdrawdag << EOF
-  > C D
-  > |/
-  > B
-  > |
-  > A
-  > EOF
-  $ root_node=$(hg log -r A -T '{node}')
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-lookup for known node works
-
-  $ sendhttpv2peer << EOF
-  > command lookup
-  >     key $root_node
-  > EOF
-  creating http peer for wire protocol version 2
-  sending lookup command
-  response: b'Bk\xad\xa5\xc6u\x98\xcae\x03mW\xd9\xe4\xb6K\x0c\x1c\xe7\xa0'
-
-  $ cat error.log
--- a/tests/test-wireproto-command-manifestdata.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,358 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ echo a0 > a
-  $ echo b0 > b
-  $ mkdir -p dir0/child0 dir0/child1 dir1
-  $ echo c0 > dir0/c
-  $ echo d0 > dir0/d
-  $ echo e0 > dir0/child0/e
-  $ echo f0 > dir0/child1/f
-  $ hg -q commit -A -m 'commit 0'
-
-  $ echo a1 > a
-  $ echo d1 > dir0/d
-  $ hg commit -m 'commit 1'
-  $ echo f0 > dir0/child1/f
-  $ hg commit -m 'commit 2'
-  nothing changed
-  [1]
-
-  $ hg -q up -r 0
-  $ echo a2 > a
-  $ hg commit -m 'commit 3'
-  created new head
-
-  $ hg log -G -T '{rev}:{node} {desc}\n'
-  @  2:c8757a2ffe552850d1e0dfe60d295ebf64c196d9 commit 3
-  |
-  | o  1:650165e803375748a94df471e5b58d85763e0b29 commit 1
-  |/
-  o  0:6d85ca1270b377d320098556ba5bfad34a9ee12d commit 0
-  
-
-  $ hg --debug debugindex -m
-     rev linkrev nodeid                                   p1                                       p2
-       0       0 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
-       1       1 91e0bdbfb0dde0023fa063edc1445f207a22eac7 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000
-       2       2 46a6721b5edaf0ea04b79a5cb3218854a4d2aba0 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Missing arguments is an error
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  abort: missing required arguments: nodes, tree
-  [255]
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[]
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  abort: missing required arguments: tree
-  [255]
-
-Unknown node is an error
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
-  >     tree eval:b''
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa (esc)
-  [255]
-
-Fetching a single revision returns just metadata by default
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    }
-  ]
-
-Requesting parents works
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0',
-      b'parents': [
-        b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-Requesting revision data works
-(haveparents defaults to false, so fulltext is emitted)
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          292
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    },
-    b'a\x000879345e39377229634b420c639454156726c6b6\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n'
-  ]
-
-haveparents=False yields same output
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'revision']
-  >     haveparents eval:False
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          292
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    },
-    b'a\x000879345e39377229634b420c639454156726c6b6\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n'
-  ]
-
-haveparents=True will emit delta
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'revision']
-  >     haveparents eval:True
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          55
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
-  ]
-
-Requesting multiple revisions works
-(haveparents defaults to false, so fulltext is emitted unless a parent
-has been emitted)
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          292
-        ]
-      ],
-      b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4'
-    },
-    b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
-    {
-      b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          55
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
-  ]
-
-With haveparents=True, first revision is a delta instead of fulltext
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'revision']
-  >     haveparents eval:True
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          292
-        ]
-      ],
-      b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4'
-    },
-    b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
-    {
-      b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          55
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
-  ]
-
-Revisions are sorted by DAG order, parents first
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0', b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4']
-  >     tree eval:b''
-  >     fields eval:[b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          292
-        ]
-      ],
-      b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4'
-    },
-    b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
-    {
-      b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          55
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
-  ]
-
-Requesting parents and revision data works
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
-  >     tree eval:b''
-  >     fields eval:[b'parents', b'revision']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 2
-    },
-    {
-      b'fieldsfollowing': [
-        [
-          b'revision',
-          292
-        ]
-      ],
-      b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
-    {
-      b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-      b'fieldsfollowing': [
-        [
-          b'delta',
-          55
-        ]
-      ],
-      b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0',
-      b'parents': [
-        b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    },
-    b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
-  ]
-
-  $ cat error.log
--- a/tests/test-wireproto-command-pushkey.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat >> .hg/hgrc << EOF
-  > [web]
-  > push_ssl = false
-  > allow-push = *
-  > EOF
-  $ hg debugdrawdag << EOF
-  > C D
-  > |/
-  > B
-  > |
-  > A
-  > EOF
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-pushkey for a bookmark works
-
-  $ sendhttpv2peer << EOF
-  > command pushkey
-  >     namespace bookmarks
-  >     key @
-  >     old
-  >     new 426bada5c67598ca65036d57d9e4b64b0c1ce7a0
-  > EOF
-  creating http peer for wire protocol version 2
-  sending pushkey command
-  response: True
-
-  $ sendhttpv2peer << EOF
-  > command listkeys
-  >     namespace bookmarks
-  > EOF
-  creating http peer for wire protocol version 2
-  sending listkeys command
-  response: {
-    b'@': b'426bada5c67598ca65036d57d9e4b64b0c1ce7a0'
-  }
-
-  $ cat error.log
--- a/tests/test-wireproto-command-rawstorefiledata.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ echo a0 > a
-  $ echo b0 > b
-  $ hg -q commit -A -m 'commit 0'
-  $ echo a1 > a
-  $ hg commit -m 'commit 1'
-  $ mkdir dir0
-  $ mkdir dir1
-  $ echo c0 > dir0/c
-  $ echo d0 > dir0/d
-  $ echo e0 > dir1/e
-  $ echo f0 > dir1/f
-  $ hg commit -A -m 'commit 2'
-  adding dir0/c
-  adding dir0/d
-  adding dir1/e
-  adding dir1/f
-  $ echo f1 > dir1/f
-  $ hg commit -m 'commit 3'
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-Missing requirement argument results in error
-
-  $ sendhttpv2peer << EOF
-  > command rawstorefiledata
-  > EOF
-  creating http peer for wire protocol version 2
-  sending rawstorefiledata command
-  abort: missing required arguments: files
-  [255]
-
-Unknown files value results in error
-
-  $ sendhttpv2peer << EOF
-  > command rawstorefiledata
-  >     files eval:[b'unknown']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending rawstorefiledata command
-  abort: unknown file type: unknown
-  [255]
-
-Requesting just changelog works
-
-  $ sendhttpv2peer << EOF
-  > command rawstorefiledata
-  >     files eval:[b'changelog']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending rawstorefiledata command
-  response: gen[
-    {
-      b'filecount': 1,
-      b'totalsize': 527 (no-zstd !)
-      b'totalsize': 530 (zstd !)
-    },
-    {
-      b'location': b'store',
-      b'path': b'00changelog.i',
-      b'size': 527 (no-zstd !)
-      b'size': 530 (zstd !)
-    },
-    b'\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00?\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u992f4779029a3df8d0666d00bb924f69634e2641\ntest\n0 0\na\nb\n\ncommit 0\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00>\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00N\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xc5\xc1\t\xc0 \x0c\x05\xd0{\xa6p\x03cjI\xd71\xf9\x11<H\xa1u\x7fJ\xf1]\x9eyu\x98\xa2\xb0Z\x88jk0\x11\x95z\xa0\xdb\x11\\\x81S\xfc*\xb4\xe2]\xc4\x89\t\xe3\xe1\xec;\xfc\x95\x1c\xbbN\xe4\xf7\x9cc%\xf9\x00S#\x19\x13\x00\x00\x00\x00\x00\xcc\x00\x00\x00\x00\x00C\x00\x00\x00B\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x85kg{\x94a\x12i\xc5lW5[\x85\xf9\x95|\xfc\xc1\xb9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u90231ddca36fa178a0eed99bd03078112487dda3\ntest\n0 0\ndir1/f\n\ncommit 3', (no-zstd !)
-    b'\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00?\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u992f4779029a3df8d0666d00bb924f69634e2641\ntest\n0 0\na\nb\n\ncommit 0\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00>\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00Q\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd WE\x02\x00r\x04\x0f\x14\x90\x01\x0e#\xf7h$;NQC%\xf8f\xd7\xb1\x81\x8d+\x01\x16+)5\xa8\x19\xdaA\xae\xe3\x00\xe9v\xe2l\x05v\x19\x11\xd4\xc1onK\xa2\x17c\xb4\xf3\xe7 z\x13\x8f\x1c\xf3j4\x03\x03\x00`\x06\x84\x8b\x1a\n\x14\x00\x00\x00\x00\x00\xcf\x00\x00\x00\x00\x00C\x00\x00\x00B\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x85kg{\x94a\x12i\xc5lW5[\x85\xf9\x95|\xfc\xc1\xb9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u90231ddca36fa178a0eed99bd03078112487dda3\ntest\n0 0\ndir1/f\n\ncommit 3', (zstd !)
-    b''
-  ]
-
-Requesting just manifestlog works (as impractical as that operation may be).
-
-  $ sendhttpv2peer << EOF
-  > command rawstorefiledata
-  >     files eval:[b'manifestlog']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending rawstorefiledata command
-  response: gen[
-    {
-      b'filecount': 1,
-      b'totalsize': 584 (no-zstd !)
-      b'totalsize': 588 (zstd !)
-    },
-    {
-      b'location': b'store',
-      b'path': b'00manifest.i',
-      b'size': 584 (no-zstd !)
-      b'size': 588 (zstd !)
-    },
-    b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00I\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c\r\xca\xc1\x11\x00!\x08\x040\xdfV\x03+\xa2\x94\xb3\x8c\xd0\x7f\twy\x87\x03i\x95r\x96F6\xe5\x1c\x9a\x10-\x16\xba|\x07\xab\xe5\xd1\xf08s\\\x8d\xc2\xbeo)w\xa9\x8b;\xa2\xff\x95\x19\x02jB\xab\x0c\xea\xf3\x03\xcf\x1d\x16\t\x00\x00\x00\x00\x00I\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x8c\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xcd\xb9\rB1\x10\x00Q\xc7\xbf\x19\xf6\xb6\xdd\x08\xb9\xf7\x92H\xa9\x90\xd2\xb8\x82\xc9\x9e4c\x8c\xfb\xf8\xf7\xca\xc7\x13n16\x8a\x88\xb2\xd8\x818`\xb4=eF\xb9f\x17\xcc\x92\x94hR\xc0\xeb\xe7s(/\x02\xcb\xd8\x13K\tU m\t\x1f\xef\xb2D\x03\xa6\xb6\x14\xb2\xaf\xc7[\rw?\x16`\xce\xd0"\x9c,\xddK\xd0c/\rIX4\xc3\xbc\xe4\xef{ u\xcc\x8c\x9c\x93]\x0f\x9cM;\n\xb7\x12-X\x1c\x96\x9fuT\xc8\xf5\x06\x88\xa25W\x00\x00\x00\x00\x01\x0c\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (no-zstd !)
-    b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd V\xfd\x01\x00b\xc5\x0e\x0f\xc0\xd1\x00\xfb\x0c\xb9\xca\xdf\xb2R\xba!\xf2\xf6\x1d\x80\xd5\x95Yc\xef9DaT\xcefcM\xf1\x12\t\x84\xf3\x1a\x04\x04N\\\'S\xf2\'\x8cz5\xc5\x9f\xfa\x18\xf3\x82W\x1a\x83Y\xe8\xf0\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x91\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd \xccE\x04\x00bK\x1e\x17\xb0A0\xff\xff\x9b\xb5V\x99\x99\xfa\xb6\xae\xf5n),"\xf1\n\x02\xb5\x07\x82++\xd1]T\x1b3\xaa\x8e\x10+)R\xa6\\\x9a\x10\xab+\xb4\x8bB\x9f\x13U\xd4\x98\xbd\xde \x9a\xf4\xd1}[\xfb{,q\x14Kf\x06\x1e\x10\xd6\x17\xbbl\x90\x16\xb9\xb3\xd8\x07\xee\xfc\xa8\x8eI\x10]\x9c\x1ava\x054W\xad\xdf\xb3\x18\xee\xbdd\x15\xdf$\x85St\n\xde\xee?\x91\xa0\x83\x11\x08\xd8\x01\x80\x10B\x04\x00\x04S\x04B\xc7Tw\x9f\xb9,\x00\x00\x00\x00\x01\x10\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (zstd !)
-    b''
-  ]
-
-Requesting both changelog and manifestlog works.
-
-  $ sendhttpv2peer << EOF
-  > command rawstorefiledata
-  >     files eval:[b'changelog', b'manifestlog']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending rawstorefiledata command
-  response: gen[
-    {
-      b'filecount': 2,
-      b'totalsize': 1111 (no-zstd !)
-      b'totalsize': 1118 (zstd !)
-    },
-    {
-      b'location': b'store',
-      b'path': b'00manifest.i',
-      b'size': 584 (no-zstd !)
-      b'size': 588 (zstd !)
-    },
-    b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00I\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c\r\xca\xc1\x11\x00!\x08\x040\xdfV\x03+\xa2\x94\xb3\x8c\xd0\x7f\twy\x87\x03i\x95r\x96F6\xe5\x1c\x9a\x10-\x16\xba|\x07\xab\xe5\xd1\xf08s\\\x8d\xc2\xbeo)w\xa9\x8b;\xa2\xff\x95\x19\x02jB\xab\x0c\xea\xf3\x03\xcf\x1d\x16\t\x00\x00\x00\x00\x00I\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x8c\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xcd\xb9\rB1\x10\x00Q\xc7\xbf\x19\xf6\xb6\xdd\x08\xb9\xf7\x92H\xa9\x90\xd2\xb8\x82\xc9\x9e4c\x8c\xfb\xf8\xf7\xca\xc7\x13n16\x8a\x88\xb2\xd8\x818`\xb4=eF\xb9f\x17\xcc\x92\x94hR\xc0\xeb\xe7s(/\x02\xcb\xd8\x13K\tU m\t\x1f\xef\xb2D\x03\xa6\xb6\x14\xb2\xaf\xc7[\rw?\x16`\xce\xd0"\x9c,\xddK\xd0c/\rIX4\xc3\xbc\xe4\xef{ u\xcc\x8c\x9c\x93]\x0f\x9cM;\n\xb7\x12-X\x1c\x96\x9fuT\xc8\xf5\x06\x88\xa25W\x00\x00\x00\x00\x01\x0c\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (no-zstd !)
-    b'\x00\x03\x00\x01\x00\x00\x00\x00\x00\x00\x00H\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd V\xfd\x01\x00b\xc5\x0e\x0f\xc0\xd1\x00\xfb\x0c\xb9\xca\xdf\xb2R\xba!\xf2\xf6\x1d\x80\xd5\x95Yc\xef9DaT\xcefcM\xf1\x12\t\x84\xf3\x1a\x04\x04N\\\'S\xf2\'\x8cz5\xc5\x9f\xfa\x18\xf3\x82W\x1a\x83Y\xe8\xf0\x00\x00\x00\x00\x00\x00H\x00\x00\x00\x00\x007\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xff\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x009a38122997b3ac97be2a9aa2e556838341fdf2cc\n\x00\x00\x00\x00\x00\x7f\x00\x00\x00\x00\x00\x91\x00\x00\x01\x16\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xbcL\xdb}\x10{\xe2w\xaa\xdb"rC\xdf\xb3\xe0M\xd5,\x81\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd \xccE\x04\x00bK\x1e\x17\xb0A0\xff\xff\x9b\xb5V\x99\x99\xfa\xb6\xae\xf5n),"\xf1\n\x02\xb5\x07\x82++\xd1]T\x1b3\xaa\x8e\x10+)R\xa6\\\x9a\x10\xab+\xb4\x8bB\x9f\x13U\xd4\x98\xbd\xde \x9a\xf4\xd1}[\xfb{,q\x14Kf\x06\x1e\x10\xd6\x17\xbbl\x90\x16\xb9\xb3\xd8\x07\xee\xfc\xa8\x8eI\x10]\x9c\x1ava\x054W\xad\xdf\xb3\x18\xee\xbdd\x15\xdf$\x85St\n\xde\xee?\x91\xa0\x83\x11\x08\xd8\x01\x80\x10B\x04\x00\x04S\x04B\xc7Tw\x9f\xb9,\x00\x00\x00\x00\x01\x10\x00\x00\x00\x00\x00<\x00\x00\x01\x16\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x90#\x1d\xdc\xa3o\xa1x\xa0\xee\xd9\x9b\xd00x\x11$\x87\xdd\xa3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe6\x00\x00\x01\x16\x00\x00\x000dir1/f\x0028c776ae08d0d55eb40648b401b90ff54448348e\n', (zstd !)
-    b'',
-    {
-      b'location': b'store',
-      b'path': b'00changelog.i',
-      b'size': 527 (no-zstd !)
-      b'size': 530 (zstd !)
-    },
-    b'\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00?\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u992f4779029a3df8d0666d00bb924f69634e2641\ntest\n0 0\na\nb\n\ncommit 0\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00>\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00N\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00x\x9c%\xc5\xc1\t\xc0 \x0c\x05\xd0{\xa6p\x03cjI\xd71\xf9\x11<H\xa1u\x7fJ\xf1]\x9eyu\x98\xa2\xb0Z\x88jk0\x11\x95z\xa0\xdb\x11\\\x81S\xfc*\xb4\xe2]\xc4\x89\t\xe3\xe1\xec;\xfc\x95\x1c\xbbN\xe4\xf7\x9cc%\xf9\x00S#\x19\x13\x00\x00\x00\x00\x00\xcc\x00\x00\x00\x00\x00C\x00\x00\x00B\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x85kg{\x94a\x12i\xc5lW5[\x85\xf9\x95|\xfc\xc1\xb9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u90231ddca36fa178a0eed99bd03078112487dda3\ntest\n0 0\ndir1/f\n\ncommit 3', (no-zstd !)
-    b'\x00\x01\x00\x01\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00?\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u992f4779029a3df8d0666d00bb924f69634e2641\ntest\n0 0\na\nb\n\ncommit 0\x00\x00\x00\x00\x00@\x00\x00\x00\x00\x00>\x00\x00\x00=\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\xff\xff\xff\xffD2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00ua988fb43583e871d1ed5750ee074c6d840bbbfc8\ntest\n0 0\na\n\ncommit 1\x00\x00\x00\x00\x00~\x00\x00\x00\x00\x00Q\x00\x00\x00W\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x01\xff\xff\xff\xff\xa4r\xd2\xea\x96U\x1a\x1e\xbb\x011-\xb2\xe6\xa7\x86\xd0F\x96o\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00(\xb5/\xfd WE\x02\x00r\x04\x0f\x14\x90\x01\x0e#\xf7h$;NQC%\xf8f\xd7\xb1\x81\x8d+\x01\x16+)5\xa8\x19\xdaA\xae\xe3\x00\xe9v\xe2l\x05v\x19\x11\xd4\xc1onK\xa2\x17c\xb4\xf3\xe7 z\x13\x8f\x1c\xf3j4\x03\x03\x00`\x06\x84\x8b\x1a\n\x14\x00\x00\x00\x00\x00\xcf\x00\x00\x00\x00\x00C\x00\x00\x00B\x00\x00\x00\x03\x00\x00\x00\x03\x00\x00\x00\x02\xff\xff\xff\xff\x85kg{\x94a\x12i\xc5lW5[\x85\xf9\x95|\xfc\xc1\xb9\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00u90231ddca36fa178a0eed99bd03078112487dda3\ntest\n0 0\ndir1/f\n\ncommit 3', (zstd !)
-    b''
-  ]
-
-  $ cat error.log
--- a/tests/test-wireproto-content-redirects.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1475 +0,0 @@
-  $ . $TESTDIR/wireprotohelpers.sh
-
-persistent-nodemap is not enabled by default. It is not relevant for this test so disable it.
-
-  $ cat >> $HGRCPATH << EOF
-  > [format]
-  > use-persistent-nodemap = no
-  > [extensions]
-  > blackbox =
-  > [blackbox]
-  > track = simplecache
-  > EOF
-
-  $ hg init server
-  $ enablehttpv2 server
-  $ cd server
-  $ cat >> .hg/hgrc << EOF
-  > [server]
-  > compressionengines = zlib
-  > [extensions]
-  > simplecache = $TESTDIR/wireprotosimplecache.py
-  > [simplecache]
-  > cacheapi = true
-  > EOF
-
-  $ echo a0 > a
-  $ echo b0 > b
-  $ hg -q commit -A -m 'commit 0'
-  $ echo a1 > a
-  $ hg commit -m 'commit 1'
-
-  $ hg --debug debugindex -m
-     rev linkrev nodeid                                   p1                                       p2
-       0       0 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
-       1       1 a988fb43583e871d1ed5750ee074c6d840bbbfc8 992f4779029a3df8d0666d00bb924f69634e2641 0000000000000000000000000000000000000000
-
-  $ hg --config simplecache.redirectsfile=redirects.py serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-  $ cat > redirects.py << EOF
-  > [
-  >   {
-  >     b'name': b'target-a',
-  >     b'protocol': b'http',
-  >     b'snirequired': False,
-  >     b'tlsversions': [b'1.2', b'1.3'],
-  >     b'uris': [b'http://example.com/'],
-  >   },
-  > ]
-  > EOF
-
-Redirect targets advertised when configured
-
-  $ sendhttpv2peerhandshake << EOF
-  > command capabilities
-  > EOF
-  creating http peer for wire protocol version 2
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 2289\r\n
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  (remote redirect target target-a is compatible) (tls1.2 !)
-  (remote redirect target target-a requires unsupported TLS versions: 1.2, 1.3) (no-tls1.2 !)
-  sending capabilities command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 111\r\n (tls1.2 !)
-  s>     content-length: 102\r\n (no-tls1.2 !)
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a (tls1.2 !)
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80 (no-tls1.2 !)
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     6de\r\n
-  s>     \xd6\x06\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: gen[
-    {
-      b'commands': {
-        b'branchmap': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'capabilities': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'changesetdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'bookmarks',
-                b'parents',
-                b'phase',
-                b'revision'
-              ])
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filedata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'path': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filesdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'dict'
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 50000
-        },
-        b'heads': {
-          b'args': {
-            b'publiconly': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'known': {
-          b'args': {
-            b'nodes': {
-              b'default': [],
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'listkeys': {
-          b'args': {
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'lookup': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'manifestdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'tree': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 100000
-        },
-        b'pushkey': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'new': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'old': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'push'
-          ]
-        },
-        b'rawstorefiledata': {
-          b'args': {
-            b'files': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        }
-      },
-      b'framingmediatypes': [
-        b'application/mercurial-exp-framing-0006'
-      ],
-      b'pathfilterprefixes': set([
-        b'path:',
-        b'rootfilesin:'
-      ]),
-      b'rawrepoformats': [
-        b'generaldelta',
-        b'revlogv1',
-        b'sparserevlog'
-      ],
-      b'redirect': {
-        b'hashes': [
-          b'sha256',
-          b'sha1'
-        ],
-        b'targets': [
-          {
-            b'name': b'target-a',
-            b'protocol': b'http',
-            b'snirequired': False,
-            b'tlsversions': [
-              b'1.2',
-              b'1.3'
-            ],
-            b'uris': [
-              b'http://example.com/'
-            ]
-          }
-        ]
-      }
-    }
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-Unknown protocol is filtered from compatible targets
-
-  $ cat > redirects.py << EOF
-  > [
-  >   {
-  >     b'name': b'target-a',
-  >     b'protocol': b'http',
-  >     b'uris': [b'http://example.com/'],
-  >   },
-  >   {
-  >     b'name': b'target-b',
-  >     b'protocol': b'unknown',
-  >     b'uris': [b'unknown://example.com/'],
-  >   },
-  > ]
-  > EOF
-
-  $ sendhttpv2peerhandshake << EOF
-  > command capabilities
-  > EOF
-  creating http peer for wire protocol version 2
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 2316\r\n
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  (remote redirect target target-a is compatible)
-  (remote redirect target target-b uses unsupported protocol: unknown)
-  sending capabilities command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 111\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81HidentityC\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81Htarget-a
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     6f9\r\n
-  s>     \xf1\x06\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: gen[
-    {
-      b'commands': {
-        b'branchmap': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'capabilities': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'changesetdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'bookmarks',
-                b'parents',
-                b'phase',
-                b'revision'
-              ])
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filedata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'path': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filesdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'dict'
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 50000
-        },
-        b'heads': {
-          b'args': {
-            b'publiconly': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'known': {
-          b'args': {
-            b'nodes': {
-              b'default': [],
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'listkeys': {
-          b'args': {
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'lookup': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'manifestdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'tree': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 100000
-        },
-        b'pushkey': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'new': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'old': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'push'
-          ]
-        },
-        b'rawstorefiledata': {
-          b'args': {
-            b'files': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        }
-      },
-      b'framingmediatypes': [
-        b'application/mercurial-exp-framing-0006'
-      ],
-      b'pathfilterprefixes': set([
-        b'path:',
-        b'rootfilesin:'
-      ]),
-      b'rawrepoformats': [
-        b'generaldelta',
-        b'revlogv1',
-        b'sparserevlog'
-      ],
-      b'redirect': {
-        b'hashes': [
-          b'sha256',
-          b'sha1'
-        ],
-        b'targets': [
-          {
-            b'name': b'target-a',
-            b'protocol': b'http',
-            b'uris': [
-              b'http://example.com/'
-            ]
-          },
-          {
-            b'name': b'target-b',
-            b'protocol': b'unknown',
-            b'uris': [
-              b'unknown://example.com/'
-            ]
-          }
-        ]
-      }
-    }
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-Missing SNI support filters targets that require SNI
-
-  $ cat > nosni.py << EOF
-  > from mercurial import sslutil
-  > sslutil.hassni = False
-  > EOF
-  $ cat >> $HGRCPATH << EOF
-  > [extensions]
-  > nosni=`pwd`/nosni.py
-  > EOF
-
-  $ cat > redirects.py << EOF
-  > [
-  >   {
-  >     b'name': b'target-bad-tls',
-  >     b'protocol': b'https',
-  >     b'uris': [b'https://example.com/'],
-  >     b'snirequired': True,
-  >   },
-  > ]
-  > EOF
-
-  $ sendhttpv2peerhandshake << EOF
-  > command capabilities
-  > EOF
-  creating http peer for wire protocol version 2
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 2276\r\n
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  (redirect target target-bad-tls requires SNI, which is unsupported)
-  sending capabilities command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 102\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     6d1\r\n
-  s>     \xc9\x06\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: gen[
-    {
-      b'commands': {
-        b'branchmap': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'capabilities': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'changesetdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'bookmarks',
-                b'parents',
-                b'phase',
-                b'revision'
-              ])
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filedata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'path': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filesdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'dict'
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 50000
-        },
-        b'heads': {
-          b'args': {
-            b'publiconly': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'known': {
-          b'args': {
-            b'nodes': {
-              b'default': [],
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'listkeys': {
-          b'args': {
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'lookup': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'manifestdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'tree': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 100000
-        },
-        b'pushkey': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'new': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'old': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'push'
-          ]
-        },
-        b'rawstorefiledata': {
-          b'args': {
-            b'files': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        }
-      },
-      b'framingmediatypes': [
-        b'application/mercurial-exp-framing-0006'
-      ],
-      b'pathfilterprefixes': set([
-        b'path:',
-        b'rootfilesin:'
-      ]),
-      b'rawrepoformats': [
-        b'generaldelta',
-        b'revlogv1',
-        b'sparserevlog'
-      ],
-      b'redirect': {
-        b'hashes': [
-          b'sha256',
-          b'sha1'
-        ],
-        b'targets': [
-          {
-            b'name': b'target-bad-tls',
-            b'protocol': b'https',
-            b'snirequired': True,
-            b'uris': [
-              b'https://example.com/'
-            ]
-          }
-        ]
-      }
-    }
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat >> $HGRCPATH << EOF
-  > [extensions]
-  > nosni=!
-  > EOF
-
-Unknown tls value is filtered from compatible targets
-
-  $ cat > redirects.py << EOF
-  > [
-  >   {
-  >     b'name': b'target-bad-tls',
-  >     b'protocol': b'https',
-  >     b'uris': [b'https://example.com/'],
-  >     b'tlsversions': [b'42', b'39'],
-  >   },
-  > ]
-  > EOF
-
-  $ sendhttpv2peerhandshake << EOF
-  > command capabilities
-  > EOF
-  creating http peer for wire protocol version 2
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /?cmd=capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
-  s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
-  s>     accept: application/mercurial-0.1\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 2282\r\n
-  s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xe4batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1,sparserevlog unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
-  (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
-  sending capabilities command
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     accept: application/mercurial-exp-framing-0006\r\n
-  s>     content-type: application/mercurial-exp-framing-0006\r\n
-  s>     content-length: 102\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     user-agent: Mercurial debugwireproto\r\n
-  s>     \r\n
-  s>     \x1c\x00\x00\x01\x00\x01\x01\x82\xa1Pcontentencodings\x81Hidentity:\x00\x00\x01\x00\x01\x00\x11\xa2DnameLcapabilitiesHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x80
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-exp-framing-0006\r\n
-  s>     Transfer-Encoding: chunked\r\n
-  s>     \r\n
-  s>     11\r\n
-  s>     \t\x00\x00\x01\x00\x02\x01\x92
-  s>     Hidentity
-  s>     \r\n
-  s>     13\r\n
-  s>     \x0b\x00\x00\x01\x00\x02\x041
-  s>     \xa1FstatusBok
-  s>     \r\n
-  s>     6d7\r\n
-  s>     \xcf\x06\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xacIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x83HlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullIfilesdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84NfirstchangesetHlinknodeGparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDdictIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullTrecommendedbatchsize\x19\xc3PEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushPrawstorefiledata\xa2Dargs\xa2Efiles\xa2Hrequired\xf5DtypeDlistJpathfilter\xa3Gdefault\xf6Hrequired\xf4DtypeDlistKpermissions\x81DpullQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x83LgeneraldeltaHrevlogv1LsparserevlogHredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
-  s>     \r\n
-  s>     8\r\n
-  s>     \x00\x00\x00\x01\x00\x02\x002
-  s>     \r\n
-  s>     0\r\n
-  s>     \r\n
-  response: gen[
-    {
-      b'commands': {
-        b'branchmap': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'capabilities': {
-          b'args': {},
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'changesetdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'bookmarks',
-                b'parents',
-                b'phase',
-                b'revision'
-              ])
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filedata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'path': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'filesdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'firstchangeset',
-                b'linknode',
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'dict'
-            },
-            b'revisions': {
-              b'required': True,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 50000
-        },
-        b'heads': {
-          b'args': {
-            b'publiconly': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'known': {
-          b'args': {
-            b'nodes': {
-              b'default': [],
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'listkeys': {
-          b'args': {
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'lookup': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        },
-        b'manifestdata': {
-          b'args': {
-            b'fields': {
-              b'default': set([]),
-              b'required': False,
-              b'type': b'set',
-              b'validvalues': set([
-                b'parents',
-                b'revision'
-              ])
-            },
-            b'haveparents': {
-              b'default': False,
-              b'required': False,
-              b'type': b'bool'
-            },
-            b'nodes': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'tree': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ],
-          b'recommendedbatchsize': 100000
-        },
-        b'pushkey': {
-          b'args': {
-            b'key': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'namespace': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'new': {
-              b'required': True,
-              b'type': b'bytes'
-            },
-            b'old': {
-              b'required': True,
-              b'type': b'bytes'
-            }
-          },
-          b'permissions': [
-            b'push'
-          ]
-        },
-        b'rawstorefiledata': {
-          b'args': {
-            b'files': {
-              b'required': True,
-              b'type': b'list'
-            },
-            b'pathfilter': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            }
-          },
-          b'permissions': [
-            b'pull'
-          ]
-        }
-      },
-      b'framingmediatypes': [
-        b'application/mercurial-exp-framing-0006'
-      ],
-      b'pathfilterprefixes': set([
-        b'path:',
-        b'rootfilesin:'
-      ]),
-      b'rawrepoformats': [
-        b'generaldelta',
-        b'revlogv1',
-        b'sparserevlog'
-      ],
-      b'redirect': {
-        b'hashes': [
-          b'sha256',
-          b'sha1'
-        ],
-        b'targets': [
-          {
-            b'name': b'target-bad-tls',
-            b'protocol': b'https',
-            b'tlsversions': [
-              b'42',
-              b'39'
-            ],
-            b'uris': [
-              b'https://example.com/'
-            ]
-          }
-        ]
-      }
-    }
-  ]
-  (sent 2 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-Set up the server to issue content redirects to its built-in API server.
-
-  $ cat > redirects.py << EOF
-  > [
-  >   {
-  >     b'name': b'local',
-  >     b'protocol': b'http',
-  >     b'uris': [b'http://example.com/'],
-  >   },
-  > ]
-  > EOF
-
-Request to eventual cache URL should return 404 (validating the cache server works)
-
-  $ sendhttpraw << EOF
-  > httprequest GET api/simplecache/missingkey
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/simplecache/missingkey HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 404 Not Found\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: text/plain\r\n
-  s>     Content-Length: 22\r\n
-  s>     \r\n
-  s>     key not found in cache
-
-Send a cacheable request
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-Cached entry should be available on server
-
-  $ sendhttpraw << EOF
-  > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c
-  >     user-agent: test
-  > EOF
-  using raw connection to peer
-  s> setsockopt(6, 1, 1) -> None (?)
-  s>     GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n
-  s>     Accept-Encoding: identity\r\n
-  s>     user-agent: test\r\n
-  s>     host: $LOCALIP:$HGPORT\r\n (glob)
-  s>     \r\n
-  s> makefile('rb', None)
-  s>     HTTP/1.1 200 OK\r\n
-  s>     Server: testing stub value\r\n
-  s>     Date: $HTTP_DATE$\r\n
-  s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 91\r\n
-  s>     \r\n
-  s>     \xa1Jtotalitems\x01\xa2DnodeT\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&AGparents\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
-  cbor> [
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-2nd request should result in content redirect response
-
-  $ sendhttpv2peer << EOF
-  > command manifestdata
-  >     nodes eval:[b'\x99\x2f\x47\x79\x02\x9a\x3d\xf8\xd0\x66\x6d\x00\xbb\x92\x4f\x69\x63\x4e\x26\x41']
-  >     tree eval:b''
-  >     fields eval:[b'parents']
-  > EOF
-  creating http peer for wire protocol version 2
-  sending manifestdata command
-  response: gen[
-    {
-      b'totalitems': 1
-    },
-    {
-      b'node': b'\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      b'parents': [
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
-        b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-      ]
-    }
-  ]
-
-  $ cat error.log
-  $ killdaemons.py
-
-  $ cat .hg/blackbox.log
-  *> cacher constructed for manifestdata (glob)
-  *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> cacher constructed for manifestdata (glob)
-  *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
-  *> sending content redirect for 47abb8efa5f01b8964d74917793ad2464db0fa2c to http://*:$HGPORT/api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
--- a/tests/test-wireproto-exchangev2-shallow.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,597 +0,0 @@
-#require sqlite
-
-Tests for wire protocol version 2 exchange.
-Tests in this file should be folded into existing tests once protocol
-v2 has enough features that it can be enabled via #testcase in existing
-tests.
-
-  $ . $TESTDIR/wireprotohelpers.sh
-  $ enablehttpv2client
-  $ cat >> $HGRCPATH << EOF
-  > [extensions]
-  > sqlitestore =
-  > pullext = $TESTDIR/pullext.py
-  > [storage]
-  > new-repo-backend=sqlite
-  > EOF
-
-Configure a server
-
-  $ hg init server-basic
-  $ enablehttpv2 server-basic
-  $ cd server-basic
-  $ mkdir dir0 dir1
-  $ echo a0 > a
-  $ echo b0 > b
-  $ hg -q commit -A -m 'commit 0'
-  $ echo c0 > dir0/c
-  $ echo d0 > dir0/d
-  $ hg -q commit -A -m 'commit 1'
-  $ echo e0 > dir1/e
-  $ echo f0 > dir1/f
-  $ hg -q commit -A -m 'commit 2'
-  $ echo c1 > dir0/c
-  $ echo e1 > dir1/e
-  $ hg commit -m 'commit 3'
-  $ echo c2 > dir0/c
-  $ echo e2 > dir1/e
-  $ echo f1 > dir1/f
-  $ hg commit -m 'commit 4'
-  $ echo a1 > a
-  $ echo b1 > b
-  $ hg commit -m 'commit 5'
-
-  $ hg log -G -T '{node} {desc}'
-  @  93a8bd067ed2840d9aa810ad598168383a3a2c3a commit 5
-  |
-  o  dc666cf9ecf3d94e6b830f30e5f1272e2a9164d9 commit 4
-  |
-  o  97765fc3cd624fd1fa0176932c21ffd16adf432e commit 3
-  |
-  o  47fe012ab237a8c7fc0c78f9f26d5866eef3f825 commit 2
-  |
-  o  b709380892b193c1091d3a817f706052e346821b commit 1
-  |
-  o  3390ef850073fbc2f0dfff2244342c8e9229013a commit 0
-  
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-  $ cd ..
-
-Shallow clone pulls down latest revision of every file
-
-  $ hg --debug clone --depth 1 http://localhost:$HGPORT client-shallow-1
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1170; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 3390ef850073
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset b709380892b1
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 47fe012ab237
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 97765fc3cd62
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset dc666cf9ecf3
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 93a8bd067ed2
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3',
-      'H]O\xc2`\xef\\\xb9\xc0p6\x88K\x00k\x11\x0ej\xdby',
-      '\xd9;\xc4\x0b\x0e*GMp\xee\xf7}^\x91/f\x7fSd\x83'
-    ],
-    'tree': ''
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1515; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'linknode',
-      'parents',
-      'revision'
-    ]),
-    'haveparents': False,
-    'revisions': [
-      {
-        'nodes': [
-          '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1005; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  updating the branch cache
-  new changesets 3390ef850073:93a8bd067ed2
-  updating to branch default
-  resolving manifests
-   branchmerge: False, force: False, partial: False
-   ancestor: 000000000000, local: 000000000000+, remote: 93a8bd067ed2
-   a: remote created -> g
-  getting a
-   b: remote created -> g
-  getting b
-   dir0/c: remote created -> g
-  getting dir0/c
-   dir0/d: remote created -> g
-  getting dir0/d
-   dir1/e: remote created -> g
-  getting dir1/e
-   dir1/f: remote created -> g
-  getting dir1/f
-  6 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-#if chg
-  $ hg --kill-chg-daemon
-  $ sleep 2
-#endif
-  $ sqlite3 -line client-shallow-1/.hg/store/db.sqlite << EOF
-  > SELECT id, path, revnum, node, p1rev, p2rev, linkrev, flags FROM filedata ORDER BY id ASC;
-  > EOF
-       id = 1
-     path = a
-   revnum = 0
-     node = \x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 2
-  
-       id = 2
-     path = b
-   revnum = 0
-     node = \xb1zk\xd3g=\x9a\xb8\xce\xd5\x81\xa2	\xf6/=\xa5\xccEx (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 2
-  
-       id = 3
-     path = dir0/c
-   revnum = 0
-     node = I\x1d\xa1\xbb\x89\xeax\xc0\xc0\xa2s[\x16\xce}\x93\x1d\xc8\xe2\r (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 2
-  
-       id = 4
-     path = dir0/d
-   revnum = 0
-     node = S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4& (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 0
-  
-       id = 5
-     path = dir1/e
-   revnum = 0
-     node = ]\xf3\xac\xd8\xd0\xc7\xfaP\x98\xd0'\x9a\x044\xc3\x02\x9e+x\xe1 (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 2
-  
-       id = 6
-     path = dir1/f
-   revnum = 0
-     node = (\xc7v\xae\x08\xd0\xd5^\xb4\x06H\xb4\x01\xb9\x0f\xf5DH4\x8e (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 2
-
-Test a shallow clone with only some files
-
-  $ hg --debug clone --depth 1 --include dir0/ http://localhost:$HGPORT client-shallow-narrow-1
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1170; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 3390ef850073
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset b709380892b1
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 47fe012ab237
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 97765fc3cd62
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset dc666cf9ecf3
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 93a8bd067ed2
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3',
-      'H]O\xc2`\xef\\\xb9\xc0p6\x88K\x00k\x11\x0ej\xdby',
-      '\xd9;\xc4\x0b\x0e*GMp\xee\xf7}^\x91/f\x7fSd\x83'
-    ],
-    'tree': ''
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1515; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'linknode',
-      'parents',
-      'revision'
-    ]),
-    'haveparents': False,
-    'pathfilter': {
-      'include': [
-        'path:dir0'
-      ]
-    },
-    'revisions': [
-      {
-        'nodes': [
-          '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=355; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  updating the branch cache
-  new changesets 3390ef850073:93a8bd067ed2
-  updating to branch default
-  resolving manifests
-   branchmerge: False, force: False, partial: False
-   ancestor: 000000000000, local: 000000000000+, remote: 93a8bd067ed2
-   dir0/c: remote created -> g
-  getting dir0/c
-   dir0/d: remote created -> g
-  getting dir0/d
-  2 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-#if chg
-  $ hg --kill-chg-daemon
-  $ sleep 2
-#endif
-  $ sqlite3 -line client-shallow-narrow-1/.hg/store/db.sqlite << EOF
-  > SELECT id, path, revnum, node, p1rev, p2rev, linkrev, flags FROM filedata ORDER BY id ASC;
-  > EOF
-       id = 1
-     path = dir0/c
-   revnum = 0
-     node = I\x1d\xa1\xbb\x89\xeax\xc0\xc0\xa2s[\x16\xce}\x93\x1d\xc8\xe2\r (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 2
-  
-       id = 2
-     path = dir0/d
-   revnum = 0
-     node = S\x82\x06\xdc\x97\x1eR\x15@\xd6\x84:\xbf\xe6\xd1`2\xf6\xd4& (esc)
-    p1rev = -1
-    p2rev = -1
-  linkrev = 5
-    flags = 0
-
-Cloning an old revision with depth=1 works
-
-  $ hg --debug clone --depth 1 -r 97765fc3cd624fd1fa0176932c21ffd16adf432e http://localhost:$HGPORT client-shallow-2
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  sending 1 commands
-  sending command lookup: {
-    'key': '97765fc3cd624fd1fa0176932c21ffd16adf432e'
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=21; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 3390ef850073
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset b709380892b1
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 47fe012ab237
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 97765fc3cd62
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3'
-    ],
-    'tree': ''
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'linknode',
-      'parents',
-      'revision'
-    ]),
-    'haveparents': False,
-    'revisions': [
-      {
-        'nodes': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1005; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  updating the branch cache
-  new changesets 3390ef850073:97765fc3cd62
-  updating to branch default
-  resolving manifests
-   branchmerge: False, force: False, partial: False
-   ancestor: 000000000000, local: 000000000000+, remote: 97765fc3cd62
-   a: remote created -> g
-  getting a
-   b: remote created -> g
-  getting b
-   dir0/c: remote created -> g
-  getting dir0/c
-   dir0/d: remote created -> g
-  getting dir0/d
-   dir1/e: remote created -> g
-  getting dir1/e
-   dir1/f: remote created -> g
-  getting dir1/f
-  6 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  updating the branch cache
-  (sent 6 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-Incremental pull of shallow clone fetches new changesets
-
-  $ hg --cwd client-shallow-2 --debug pull http://localhost:$HGPORT
-  pulling from http://localhost:$HGPORT/
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': [
-      '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  searching for changes
-  all local changesets known remotely
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:'
-        ],
-        'roots': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=400; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset dc666cf9ecf3
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  add changeset 93a8bd067ed2
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos) (?)
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      'H]O\xc2`\xef\\\xb9\xc0p6\x88K\x00k\x11\x0ej\xdby',
-      '\xd9;\xc4\x0b\x0e*GMp\xee\xf7}^\x91/f\x7fSd\x83'
-    ],
-    'tree': ''
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=561; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'linknode',
-      'parents',
-      'revision'
-    ]),
-    'haveparents': False,
-    'revisions': [
-      {
-        'nodes': [
-          '\xdcfl\xf9\xec\xf3\xd9Nk\x83\x0f0\xe5\xf1\'.*\x91d\xd9',
-          '\x93\xa8\xbd\x06~\xd2\x84\r\x9a\xa8\x10\xadY\x81h8::,:'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1373; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  updating the branch cache
-  new changesets dc666cf9ecf3:93a8bd067ed2
-  (run 'hg update' to get a working copy)
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ hg --cwd client-shallow-2 up tip
-  merging dir0/c
-  merging dir1/e
-  3 files updated, 2 files merged, 0 files removed, 0 files unresolved
--- a/tests/test-wireproto-exchangev2.t	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1392 +0,0 @@
-Tests for wire protocol version 2 exchange.
-Tests in this file should be folded into existing tests once protocol
-v2 has enough features that it can be enabled via #testcase in existing
-tests.
-
-  $ . $TESTDIR/wireprotohelpers.sh
-  $ enablehttpv2client
-
-  $ hg init server-simple
-  $ enablehttpv2 server-simple
-  $ cd server-simple
-  $ cat >> .hg/hgrc << EOF
-  > [phases]
-  > publish = false
-  > EOF
-  $ echo a0 > a
-  $ echo b0 > b
-  $ hg -q commit -A -m 'commit 0'
-
-  $ echo a1 > a
-  $ hg commit -m 'commit 1'
-  $ hg phase --public -r .
-  $ echo a2 > a
-  $ hg commit -m 'commit 2'
-
-  $ hg -q up -r 0
-  $ echo b1 > b
-  $ hg -q commit -m 'head 2 commit 1'
-  $ echo b2 > b
-  $ hg -q commit -m 'head 2 commit 2'
-
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-  $ cd ..
-
-Test basic clone
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug clone -U http://localhost:$HGPORT client-simple > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset 4432d83626e8
-  add changeset cd2534766bec
-  add changeset e96ae20f4188
-  add changeset caa2a465451d
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
-      '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5',
-      '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f',
-      '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
-          '\xe9j\xe2\x0fA\x88H{\x9a\xe4\xef9A\xc2|\x81\x141F\xe5',
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets 3390ef850073:caa2a465451d (3 drafts)
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=941; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=992; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=901; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-All changesets should have been transferred
-
-  $ hg -R client-simple debugindex -c
-     rev linkrev nodeid       p1           p2
-       0       0 3390ef850073 000000000000 000000000000
-       1       1 4432d83626e8 3390ef850073 000000000000
-       2       2 cd2534766bec 4432d83626e8 000000000000
-       3       3 e96ae20f4188 3390ef850073 000000000000
-       4       4 caa2a465451d e96ae20f4188 000000000000
-
-  $ hg -R client-simple log -G -T '{rev} {node} {phase}\n'
-  o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
-  |
-  o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
-  |
-  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
-  | |
-  | o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
-  |/
-  o  0 3390ef850073fbc2f0dfff2244342c8e9229013a public
-  
-
-All manifests should have been transferred
-
-  $ hg -R client-simple debugindex -m
-     rev linkrev nodeid       p1           p2
-       0       0 992f4779029a 000000000000 000000000000
-       1       1 a988fb43583e 992f4779029a 000000000000
-       2       2 ec804e488c20 a988fb43583e 000000000000
-       3       3 045c7f3927da 992f4779029a 000000000000
-       4       4 379cb0c2e664 045c7f3927da 000000000000
-
-Cloning only a specific revision works
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug clone -U -r 4432d83626e8 http://localhost:$HGPORT client-singlehead > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  sending 1 commands
-  sending command lookup: {
-    'key': '4432d83626e8'
-  }
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset 4432d83626e8
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets 3390ef850073:4432d83626e8
-  updating the branch cache
-  (sent 6 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=21; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=381; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=404; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=439; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-  $ cd client-singlehead
-
-  $ hg log -G -T '{rev} {node} {phase}\n'
-  o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
-  |
-  o  0 3390ef850073fbc2f0dfff2244342c8e9229013a public
-  
-
-  $ hg debugindex -m
-     rev linkrev nodeid       p1           p2
-       0       0 992f4779029a 000000000000 000000000000
-       1       1 a988fb43583e 992f4779029a 000000000000
-
-Incremental pull works
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug pull > pull-output
-
-  $ cat pull-output | grep -v "received frame"
-  pulling from http://localhost:$HGPORT/
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': [
-      'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
-    ]
-  }
-  searching for changes
-  all local changesets known remotely
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'roots': [
-          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
-        ],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset cd2534766bec
-  add changeset e96ae20f4188
-  add changeset caa2a465451d
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5',
-      '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f',
-      '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'revisions': [
-      {
-        'nodes': [
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
-          '\xe9j\xe2\x0fA\x88H{\x9a\xe4\xef9A\xc2|\x81\x141F\xe5',
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets cd2534766bec:caa2a465451d (3 drafts)
-  (run 'hg update' to get a working copy)
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat pull-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=573; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=601; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=527; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm pull-output
-
-  $ hg log -G -T '{rev} {node} {phase}\n'
-  o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
-  |
-  o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
-  |
-  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
-  | |
-  | o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
-  |/
-  o  0 3390ef850073fbc2f0dfff2244342c8e9229013a public
-  
-
-  $ hg debugindex -m
-     rev linkrev nodeid       p1           p2
-       0       0 992f4779029a 000000000000 000000000000
-       1       1 a988fb43583e 992f4779029a 000000000000
-       2       2 ec804e488c20 a988fb43583e 000000000000
-       3       3 045c7f3927da 992f4779029a 000000000000
-       4       4 379cb0c2e664 045c7f3927da 000000000000
-
-Phase-only update works
-TODO this doesn't work
-
-  $ hg -R ../server-simple phase --public -r caa2a465451dd
-  $ hg --debug pull
-  pulling from http://localhost:$HGPORT/
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': [
-      '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
-      '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=3; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  searching for changes
-  all remote heads known locally
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'roots': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=13; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  checking for updated bookmarks
-  (run 'hg update' to get a working copy)
-  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ hg log -G -T '{rev} {node} {phase}\n'
-  o  4 caa2a465451dd1facda0f5b12312c355584188a1 draft
-  |
-  o  3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
-  |
-  | o  2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
-  | |
-  | o  1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
-  |/
-  o  0 3390ef850073fbc2f0dfff2244342c8e9229013a public
-  
-
-  $ cd ..
-
-Bookmarks are transferred on clone
-
-  $ hg -R server-simple bookmark -r 3390ef850073fbc2f0dfff2244342c8e9229013a book-1
-  $ hg -R server-simple bookmark -r cd2534766bece138c7c1afdc6825302f0f62d81f book-2
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug clone -U http://localhost:$HGPORT/ client-bookmarks > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset 4432d83626e8
-  add changeset cd2534766bec
-  add changeset e96ae20f4188
-  add changeset caa2a465451d
-  checking for updated bookmarks
-  adding remote bookmark book-1
-  adding remote bookmark book-2
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
-      '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5',
-      '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f',
-      '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
-          '\xe9j\xe2\x0fA\x88H{\x9a\xe4\xef9A\xc2|\x81\x141F\xe5',
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets 3390ef850073:caa2a465451d (1 drafts)
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=979; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=992; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=901; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-  $ hg -R client-bookmarks bookmarks
-     book-1                    0:3390ef850073
-     book-2                    2:cd2534766bec
-
-Server-side bookmark moves are reflected during `hg pull`
-
-  $ hg -R server-simple bookmark -r cd2534766bece138c7c1afdc6825302f0f62d81f book-1
-  moving bookmark 'book-1' forward from 3390ef850073
-
-Output is flaky, save it in a file and check part independently
-  $ hg -R client-bookmarks --debug pull > pull-output
-
-  $ cat pull-output | grep -v "received frame"
-  pulling from http://localhost:$HGPORT/
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': [
-      '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
-      '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
-    ]
-  }
-  searching for changes
-  all remote heads known locally
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'roots': [
-          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-        ],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  checking for updated bookmarks
-  updating bookmark book-1
-  (run 'hg update' to get a working copy)
-  (sent 3 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat pull-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=43; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=3; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=65; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm pull-output
-
-  $ hg -R client-bookmarks bookmarks
-     book-1                    2:cd2534766bec
-     book-2                    2:cd2534766bec
-
-  $ killdaemons.py
-
-Let's set up a slightly more complicated server
-
-  $ hg init server-2
-  $ enablehttpv2 server-2
-  $ cd server-2
-  $ mkdir dir0 dir1
-  $ echo a0 > a
-  $ echo b0 > b
-  $ hg -q commit -A -m 'commit 0'
-  $ echo c0 > dir0/c
-  $ echo d0 > dir0/d
-  $ hg -q commit -A -m 'commit 1'
-  $ echo e0 > dir1/e
-  $ echo f0 > dir1/f
-  $ hg -q commit -A -m 'commit 2'
-  $ echo c1 > dir0/c
-  $ echo e1 > dir1/e
-  $ hg commit -m 'commit 3'
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-
-  $ cd ..
-
-Narrow clone only fetches some files
-
-Output is flaky, save it in a file and check part independently
-  $ hg --config extensions.pullext=$TESTDIR/pullext.py --debug clone -U --include dir0/ http://localhost:$HGPORT/ client-narrow-0 > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset b709380892b1
-  add changeset 47fe012ab237
-  add changeset 97765fc3cd62
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'pathfilter': {
-      'include': [
-        'path:dir0'
-      ]
-    },
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b',
-          'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%',
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets 3390ef850073:97765fc3cd62
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=449; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-#if reporevlogstore
-  $ find client-narrow-0/.hg/store -type f -name '*.i' | sort
-  client-narrow-0/.hg/store/00changelog.i
-  client-narrow-0/.hg/store/00manifest.i
-  client-narrow-0/.hg/store/data/dir0/c.i
-  client-narrow-0/.hg/store/data/dir0/d.i
-#endif
-
---exclude by itself works
-
-Output is flaky, save it in a file and check part independently
-  $ hg --config extensions.pullext=$TESTDIR/pullext.py --debug clone -U --exclude dir0/ http://localhost:$HGPORT/ client-narrow-1 > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset b709380892b1
-  add changeset 47fe012ab237
-  add changeset 97765fc3cd62
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'pathfilter': {
-      'exclude': [
-        'path:dir0'
-      ],
-      'include': [
-        'path:.'
-      ]
-    },
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b',
-          'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%',
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets 3390ef850073:97765fc3cd62
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=709; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-#if reporevlogstore
-  $ find client-narrow-1/.hg/store -type f -name '*.i' | sort
-  client-narrow-1/.hg/store/00changelog.i
-  client-narrow-1/.hg/store/00manifest.i
-  client-narrow-1/.hg/store/data/a.i
-  client-narrow-1/.hg/store/data/b.i
-  client-narrow-1/.hg/store/data/dir1/e.i
-  client-narrow-1/.hg/store/data/dir1/f.i
-#endif
-
-Mixing --include and --exclude works
-
-Output is flaky, save it in a file and check part independently
-  $ hg --config extensions.pullext=$TESTDIR/pullext.py --debug clone -U --include dir0/ --exclude dir0/c http://localhost:$HGPORT/ client-narrow-2 > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset b709380892b1
-  add changeset 47fe012ab237
-  add changeset 97765fc3cd62
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'pathfilter': {
-      'exclude': [
-        'path:dir0/c'
-      ],
-      'include': [
-        'path:dir0'
-      ]
-    },
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b',
-          'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%',
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  new changesets 3390ef850073:97765fc3cd62
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=160; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-#if reporevlogstore
-  $ find client-narrow-2/.hg/store -type f -name '*.i' | sort
-  client-narrow-2/.hg/store/00changelog.i
-  client-narrow-2/.hg/store/00manifest.i
-  client-narrow-2/.hg/store/data/dir0/d.i
-#endif
-
---stream will use rawfiledata to transfer changelog and manifestlog, then
-fall through to get files data
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug clone --stream -U http://localhost:$HGPORT client-stream-0 > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  sending 1 commands
-  sending command rawstorefiledata: {
-    'files': [
-      'changelog',
-      'manifestlog'
-    ]
-  }
-  updating the branch cache
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': [
-      '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-    ]
-  }
-  searching for changes
-  all remote heads known locally
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  checking for updated bookmarks
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b',
-          'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%',
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1275; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (no-zstd !)
-  received frame(size=1283; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (zstd !)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=13; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1133; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
---stream + --include/--exclude will only obtain some files
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug --config extensions.pullext=$TESTDIR/pullext.py clone --stream --include dir0/ -U http://localhost:$HGPORT client-stream-2 > clone-output
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  sending 1 commands
-  sending command rawstorefiledata: {
-    'files': [
-      'changelog',
-      'manifestlog'
-    ]
-  }
-  updating the branch cache
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': [
-      '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-    ]
-  }
-  searching for changes
-  all remote heads known locally
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  checking for updated bookmarks
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'pathfilter': {
-      'include': [
-        'path:dir0'
-      ]
-    },
-    'revisions': [
-      {
-        'nodes': [
-          '3\x90\xef\x85\x00s\xfb\xc2\xf0\xdf\xff"D4,\x8e\x92)\x01:',
-          '\xb7\t8\x08\x92\xb1\x93\xc1\t\x1d:\x81\x7fp`R\xe3F\x82\x1b',
-          'G\xfe\x01*\xb27\xa8\xc7\xfc\x0cx\xf9\xf2mXf\xee\xf3\xf8%',
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  updating the branch cache
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1275; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (no-zstd !)
-  received frame(size=1283; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation) (zstd !)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=2; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=13; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=449; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-#if reporevlogstore
-  $ find client-stream-2/.hg/store -type f -name '*.i' | sort
-  client-stream-2/.hg/store/00changelog.i
-  client-stream-2/.hg/store/00manifest.i
-  client-stream-2/.hg/store/data/dir0/c.i
-  client-stream-2/.hg/store/data/dir0/d.i
-#endif
-
-Shallow clone doesn't work with revlogs
-
-Output is flaky, save it in a file and check part independently
-  $ hg --debug --config extensions.pullext=$TESTDIR/pullext.py clone --depth 1 -U http://localhost:$HGPORT client-shallow-revlogs > clone-output
-  transaction abort!
-  rollback completed
-  abort: revlog storage does not support missing parents write mode
-  [255]
-
-  $ cat clone-output | grep -v "received frame"
-  using http://localhost:$HGPORT/
-  sending capabilities command
-  query 1; heads
-  sending 2 commands
-  sending command heads: {}
-  sending command known: {
-    'nodes': []
-  }
-  sending 1 commands
-  sending command changesetdata: {
-    'fields': set([
-      'bookmarks',
-      'parents',
-      'phase',
-      'revision'
-    ]),
-    'revisions': [
-      {
-        'heads': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'roots': [],
-        'type': 'changesetdagrange'
-      }
-    ]
-  }
-  add changeset 3390ef850073
-  add changeset b709380892b1
-  add changeset 47fe012ab237
-  add changeset 97765fc3cd62
-  checking for updated bookmarks
-  sending 1 commands
-  sending command manifestdata: {
-    'fields': set([
-      'parents',
-      'revision'
-    ]),
-    'haveparents': True,
-    'nodes': [
-      '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
-      '|2 \x1a\xa3\xa1R\xa9\xe6\xa9"+?\xa8\xd0\xe3\x0f\xc2V\xe8',
-      '\x8d\xd0W<\x7f\xaf\xe2\x04F\xcc\xea\xac\x05N\xea\xa4x\x91M\xdb',
-      '113\x85\xf2!\x8b\x08^\xb2Z\x821\x1e*\xdd\x0e\xeb\x8c3'
-    ],
-    'tree': ''
-  }
-  sending 1 commands
-  sending command filesdata: {
-    'fields': set([
-      'linknode',
-      'parents',
-      'revision'
-    ]),
-    'haveparents': False,
-    'revisions': [
-      {
-        'nodes': [
-          '\x97v_\xc3\xcdbO\xd1\xfa\x01v\x93,!\xff\xd1j\xdfC.'
-        ],
-        'type': 'changesetexplicit'
-      }
-    ]
-  }
-  (sent 5 HTTP requests and * bytes; received * bytes in responses) (glob)
-
-  $ cat clone-output | grep "received frame"
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=22; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=11; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1; request=3; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=783; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=967; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-  received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
-  received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=1005; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
-
-  $ rm clone-output
-
-  $ killdaemons.py
-
-Repo with 2 DAG branches introducing same filenode, to test linknode adjustment
-
-  $ hg init server-linknode
-  $ enablehttpv2 server-linknode
-  $ cd server-linknode
-  $ touch foo
-  $ hg -q commit -Am initial
-  $ echo foo > dupe-file
-  $ hg commit -Am 'dupe 1'
-  adding dupe-file
-  $ hg -q up -r 0
-  $ echo foo > dupe-file
-  $ hg commit -Am 'dupe 2'
-  adding dupe-file
-  created new head
-  $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
-  $ cat hg.pid > $DAEMON_PIDS
-  $ cd ..
-
-Perform an incremental pull of both heads and ensure linkrev is written out properly
-
-  $ hg clone -r 96ee1d7354c4 http://localhost:$HGPORT client-linknode-1
-  new changesets 96ee1d7354c4
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ cd client-linknode-1
-  $ touch extra
-  $ hg commit -Am extra
-  adding extra
-  $ cd ..
-
-  $ hg clone -r 96ee1d7354c4 http://localhost:$HGPORT client-linknode-2
-  new changesets 96ee1d7354c4
-  updating to branch default
-  1 files updated, 0 files merged, 0 files removed, 0 files unresolved
-  $ cd client-linknode-2
-  $ touch extra
-  $ hg commit -Am extra
-  adding extra
-  $ cd ..
-
-  $ hg -R client-linknode-1 pull -r 1681c33f9f80
-  pulling from http://localhost:$HGPORT/
-  searching for changes
-  new changesets 1681c33f9f80
-  (run 'hg update' to get a working copy)
-
-#if reporevlogstore
-  $ hg -R client-linknode-1 debugrevlogindex dupe-file
-     rev linkrev nodeid       p1           p2
-       0       2 2ed2a3912a0b 000000000000 000000000000
-#endif
-
-  $ hg -R client-linknode-2 pull -r 639c8990d6a5
-  pulling from http://localhost:$HGPORT/
-  searching for changes
-  new changesets 639c8990d6a5
-  (run 'hg update' to get a working copy)
-
-#if reporevlogstore
-  $ hg -R client-linknode-2 debugrevlogindex dupe-file
-     rev linkrev nodeid       p1           p2
-       0       2 2ed2a3912a0b 000000000000 000000000000
-#endif
--- a/tests/wireprotohelpers.sh	Thu Dec 30 13:25:44 2021 +0100
+++ b/tests/wireprotohelpers.sh	Tue Dec 07 16:44:22 2021 +0100
@@ -1,44 +1,23 @@
-HTTPV2=exp-http-v2-0003
 MEDIATYPE=application/mercurial-exp-framing-0006
 
 sendhttpraw() {
   hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT/
 }
 
-sendhttpv2peer() {
-  hg --config experimental.httppeer.v2-encoder-order=identity debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/
-}
-
-sendhttpv2peerverbose() {
-  hg --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto --nologhandshake --peer http2 http://$LOCALIP:$HGPORT/
-}
-
-sendhttpv2peerhandshake() {
-  hg --config experimental.httppeer.v2-encoder-order=identity --verbose debugwireproto --peer http2 http://$LOCALIP:$HGPORT/
-}
-
 cat > dummycommands.py << EOF
 from mercurial import (
     wireprototypes,
     wireprotov1server,
-    wireprotov2server,
 )
 
 @wireprotov1server.wireprotocommand(b'customreadonly', permission=b'pull')
 def customreadonlyv1(repo, proto):
     return wireprototypes.bytesresponse(b'customreadonly bytes response')
 
-@wireprotov2server.wireprotocommand(b'customreadonly', permission=b'pull')
-def customreadonlyv2(repo, proto):
-    yield b'customreadonly bytes response'
-
 @wireprotov1server.wireprotocommand(b'customreadwrite', permission=b'push')
 def customreadwrite(repo, proto):
     return wireprototypes.bytesresponse(b'customreadwrite bytes response')
 
-@wireprotov2server.wireprotocommand(b'customreadwrite', permission=b'push')
-def customreadwritev2(repo, proto):
-    yield b'customreadwrite bytes response'
 EOF
 
 cat >> $HGRCPATH << EOF
@@ -53,20 +32,3 @@
 EOF
 }
 
-enablehttpv2() {
-  cat >> $1/.hg/hgrc << EOF
-[experimental]
-web.apiserver = true
-web.api.http-v2 = true
-EOF
-}
-
-enablehttpv2client() {
-  cat >> $HGRCPATH << EOF
-[experimental]
-httppeer.advertise-v2 = true
-# So tests are in plain text. Also, zstd isn't available in all installs,
-# which would make tests non-deterministic.
-httppeer.v2-encoder-order = identity
-EOF
-}
--- a/tests/wireprotosimplecache.py	Thu Dec 30 13:25:44 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,220 +0,0 @@
-# wireprotosimplecache.py - Extension providing in-memory wire protocol cache
-#
-# Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
-#
-# This software may be used and distributed according to the terms of the
-# GNU General Public License version 2 or any later version.
-
-from __future__ import absolute_import
-
-from mercurial import (
-    extensions,
-    registrar,
-    util,
-    wireprotoserver,
-    wireprototypes,
-    wireprotov2server,
-)
-from mercurial.interfaces import (
-    repository,
-    util as interfaceutil,
-)
-from mercurial.utils import stringutil
-
-CACHE = None
-
-configtable = {}
-configitem = registrar.configitem(configtable)
-
-configitem(b'simplecache', b'cacheapi', default=False)
-configitem(b'simplecache', b'cacheobjects', default=False)
-configitem(b'simplecache', b'redirectsfile', default=None)
-
-# API handler that makes cached keys available.
-def handlecacherequest(rctx, req, res, checkperm, urlparts):
-    if rctx.repo.ui.configbool(b'simplecache', b'cacheobjects'):
-        res.status = b'500 Internal Server Error'
-        res.setbodybytes(b'cacheobjects not supported for api server')
-        return
-
-    if not urlparts:
-        res.status = b'200 OK'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(b'simple cache server')
-        return
-
-    key = b'/'.join(urlparts)
-
-    if key not in CACHE:
-        res.status = b'404 Not Found'
-        res.headers[b'Content-Type'] = b'text/plain'
-        res.setbodybytes(b'key not found in cache')
-        return
-
-    res.status = b'200 OK'
-    res.headers[b'Content-Type'] = b'application/mercurial-cbor'
-    res.setbodybytes(CACHE[key])
-
-
-def cachedescriptor(req, repo):
-    return {}
-
-
-wireprotoserver.API_HANDLERS[b'simplecache'] = {
-    b'config': (b'simplecache', b'cacheapi'),
-    b'handler': handlecacherequest,
-    b'apidescriptor': cachedescriptor,
-}
-
-
-@interfaceutil.implementer(repository.iwireprotocolcommandcacher)
-class memorycacher(object):
-    def __init__(
-        self, ui, command, encodefn, redirecttargets, redirecthashes, req
-    ):
-        self.ui = ui
-        self.encodefn = encodefn
-        self.redirecttargets = redirecttargets
-        self.redirecthashes = redirecthashes
-        self.req = req
-        self.key = None
-        self.cacheobjects = ui.configbool(b'simplecache', b'cacheobjects')
-        self.cacheapi = ui.configbool(b'simplecache', b'cacheapi')
-        self.buffered = []
-
-        ui.log(b'simplecache', b'cacher constructed for %s\n', command)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exctype, excvalue, exctb):
-        if exctype:
-            self.ui.log(b'simplecache', b'cacher exiting due to error\n')
-
-    def adjustcachekeystate(self, state):
-        # Needed in order to make tests deterministic. Don't copy this
-        # pattern for production caches!
-        del state[b'repo']
-
-    def setcachekey(self, key):
-        self.key = key
-        return True
-
-    def lookup(self):
-        if self.key not in CACHE:
-            self.ui.log(b'simplecache', b'cache miss for %s\n', self.key)
-            return None
-
-        entry = CACHE[self.key]
-        self.ui.log(b'simplecache', b'cache hit for %s\n', self.key)
-
-        redirectable = True
-
-        if not self.cacheapi:
-            redirectable = False
-        elif not self.redirecttargets:
-            redirectable = False
-        else:
-            clienttargets = set(self.redirecttargets)
-            ourtargets = {t[b'name'] for t in loadredirecttargets(self.ui)}
-
-            # We only ever redirect to a single target (for now). So we don't
-            # need to store which target matched.
-            if not clienttargets & ourtargets:
-                redirectable = False
-
-        if redirectable:
-            paths = self.req.dispatchparts[:-3]
-            paths.append(b'simplecache')
-            paths.append(self.key)
-
-            url = b'%s/%s' % (self.req.baseurl, b'/'.join(paths))
-
-            # url = b'http://example.com/%s' % self.key
-            self.ui.log(
-                b'simplecache',
-                b'sending content redirect for %s to ' b'%s\n',
-                self.key,
-                url,
-            )
-            response = wireprototypes.alternatelocationresponse(
-                url=url, mediatype=b'application/mercurial-cbor'
-            )
-
-            return {b'objs': [response]}
-
-        if self.cacheobjects:
-            return {
-                b'objs': entry,
-            }
-        else:
-            return {
-                b'objs': [wireprototypes.encodedresponse(entry)],
-            }
-
-    def onobject(self, obj):
-        if self.cacheobjects:
-            self.buffered.append(obj)
-        else:
-            self.buffered.extend(self.encodefn(obj))
-
-        yield obj
-
-    def onfinished(self):
-        self.ui.log(b'simplecache', b'storing cache entry for %s\n', self.key)
-        if self.cacheobjects:
-            CACHE[self.key] = self.buffered
-        else:
-            CACHE[self.key] = b''.join(self.buffered)
-
-        return []
-
-
-def makeresponsecacher(
-    orig,
-    repo,
-    proto,
-    command,
-    args,
-    objencoderfn,
-    redirecttargets,
-    redirecthashes,
-):
-    return memorycacher(
-        repo.ui,
-        command,
-        objencoderfn,
-        redirecttargets,
-        redirecthashes,
-        proto._req,
-    )
-
-
-def loadredirecttargets(ui):
-    path = ui.config(b'simplecache', b'redirectsfile')
-    if not path:
-        return []
-
-    with open(path, 'rb') as fh:
-        s = fh.read()
-
-    return stringutil.evalpythonliteral(s)
-
-
-def getadvertisedredirecttargets(orig, repo, proto):
-    return loadredirecttargets(repo.ui)
-
-
-def extsetup(ui):
-    global CACHE
-
-    CACHE = util.lrucachedict(10000)
-
-    extensions.wrapfunction(
-        wireprotov2server, b'makeresponsecacher', makeresponsecacher
-    )
-    extensions.wrapfunction(
-        wireprotov2server,
-        b'getadvertisedredirecttargets',
-        getadvertisedredirecttargets,
-    )