Patchwork D2392: debugcommands: add debugwireproto command

login
register
mail settings
Submitter phabricator
Date March 1, 2018, 4:31 p.m.
Message ID <e39edce695635b74f66b367166524505@localhost.localdomain>
Download mbox | patch
Permalink /patch/28564/
State Not Applicable
Headers show

Comments

phabricator - March 1, 2018, 4:31 p.m.
indygreg updated this revision to Diff 6250.

REPOSITORY
  rHG Mercurial

CHANGES SINCE LAST UPDATE
  https://phab.mercurial-scm.org/D2392?vs=6139&id=6250

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

AFFECTED FILES
  mercurial/debugcommands.py
  tests/test-completion.t
  tests/test-help.t
  tests/test-ssh-proto.t

CHANGE DETAILS




To: indygreg, #hg-reviewers, yuja
Cc: yuja, sid0, mercurial-devel

Patch

diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t
--- a/tests/test-ssh-proto.t
+++ b/tests/test-ssh-proto.t
@@ -12,10 +12,29 @@ 
   $ echo 0 > foo
   $ hg -q add foo
   $ hg commit -m initial
-  $ cd ..
+
+A no-op connection performs a handshake
+
+  $ hg debugwireproto --localssh << EOF
+  > EOF
+  creating ssh peer from handshake results
+
+Raw peers don't perform any activity
+
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > EOF
+  using raw connection to peer
+  $ 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
 
+  $ cd ..
+
   $ hg --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user@dummy" "hg -R server serve --stdio" (glob) (windows !)
@@ -33,11 +52,19 @@ 
 
 Server should answer the "hello" command in isolation
 
-  $ hg -R server serve --stdio << EOF
-  > hello
+  $ hg -R server debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     hello\n
+  > readline
+  > readline
   > EOF
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  using raw connection to peer
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
 
 `hg debugserve --sshstdio` works
 
@@ -80,16 +107,33 @@ 
 Server should reply with capabilities and should send "1\n\n" as a successful
 reply with empty response to the "between".
 
-  $ hg -R server serve --stdio << EOF
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg -R server debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
 SSH banner is not printed by default, ignored by clients
 
@@ -127,26 +171,63 @@ 
 
 And test the banner with the raw protocol
 
-  $ SSHSERVERMODE=banner hg -R server serve --stdio << EOF
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ SSHSERVERMODE=banner hg -R server debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  banner: line 0
-  banner: line 1
-  banner: line 2
-  banner: line 3
-  banner: line 4
-  banner: line 5
-  banner: line 6
-  banner: line 7
-  banner: line 8
-  banner: line 9
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 15:
+  o>     banner: line 0\n
+  o> readline() -> 15:
+  o>     banner: line 1\n
+  o> readline() -> 15:
+  o>     banner: line 2\n
+  o> readline() -> 15:
+  o>     banner: line 3\n
+  o> readline() -> 15:
+  o>     banner: line 4\n
+  o> readline() -> 15:
+  o>     banner: line 5\n
+  o> readline() -> 15:
+  o>     banner: line 6\n
+  o> readline() -> 15:
+  o>     banner: line 7\n
+  o> readline() -> 15:
+  o>     banner: line 8\n
+  o> readline() -> 15:
+  o>     banner: line 9\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
 Connecting to a <0.9.1 server that doesn't support the hello command.
 The client should refuse, as we dropped support for connecting to such
@@ -167,18 +248,37 @@ 
 
 Sending an unknown command to the server results in an empty response to that command
 
-  $ hg -R server serve --stdio << EOF
-  > pre-hello
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg -R server debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     pre-hello\n
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(10) -> None:
+  i>     pre-hello\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  o> readline() -> 2:
+  o>     1\n
 
   $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-no-args --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
@@ -199,22 +299,54 @@ 
 
 Send multiple unknown commands before hello
 
-  $ hg -R server serve --stdio << EOF
-  > unknown1
-  > unknown2
-  > unknown3
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg -R server debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown1\n
+  > readline
+  > raw
+  >     unknown2\n
+  > readline
+  > raw
+  >     unknown3\n
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(9) -> None:
+  i>     unknown1\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(9) -> None:
+  i>     unknown2\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(9) -> None:
+  i>     unknown3\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
   $ hg --config sshpeer.mode=extra-handshake-commands --config sshpeer.handshake-mode=pre-multiple-no-args --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
@@ -239,239 +371,557 @@ 
 
 Send an unknown command before hello that has arguments
 
-  $ hg -R server serve --stdio << EOF
-  > with-args
-  > foo 13
-  > value for foo
-  > bar 13
-  > value for bar
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ cd server
+
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     with-args\n
+  >     foo 13\n
+  >     value for foo\n
+  >     bar 13\n
+  >     value for bar\n
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  0
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(52) -> None:
+  i>     with-args\n
+  i>     foo 13\n
+  i>     value for foo\n
+  i>     bar 13\n
+  i>     value for bar\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
 Send an unknown command having an argument that looks numeric
 
-  $ hg -R server serve --stdio << EOF
-  > unknown
-  > foo 1
-  > 0
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown\n
+  >     foo 1\n
+  >     0\n
+  > readline
+  > readline
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(16) -> None:
+  i>     unknown\n
+  i>     foo 1\n
+  i>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
-  $ hg -R server serve --stdio << EOF
-  > unknown
-  > foo 1
-  > 1
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown\n
+  >     foo 1\n
+  >     1\n
+  > readline
+  > readline
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(16) -> None:
+  i>     unknown\n
+  i>     foo 1\n
+  i>     1\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
 When sending a dict argument value, it is serialized to
 "<arg> <item count>" followed by "<key> <len>\n<value>" for each item
 in the dict.
 
 Dictionary value for unknown command
 
-  $ hg -R server serve --stdio << EOF
-  > unknown
-  > dict 3
-  > key1 3
-  > foo
-  > key2 3
-  > bar
-  > key3 3
-  > baz
-  > hello
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown\n
+  >     dict 3\n
+  >     key1 3\n
+  >     foo\n
+  >     key2 3\n
+  >     bar\n
+  >     key3 3\n
+  >     baz\n
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  0
-  0
-  0
-  0
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  using raw connection to peer
+  i> write(48) -> None:
+  i>     unknown\n
+  i>     dict 3\n
+  i>     key1 3\n
+  i>     foo\n
+  i>     key2 3\n
+  i>     bar\n
+  i>     key3 3\n
+  i>     baz\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
 
 Incomplete dictionary send
 
-  $ hg -R server serve --stdio << EOF
-  > unknown
-  > dict 3
-  > key1 3
-  > foo
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown\n
+  >     dict 3\n
+  >     key1 3\n
+  >     foo\n
+  > readline
+  > readline
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  0
+  using raw connection to peer
+  i> write(26) -> None:
+  i>     unknown\n
+  i>     dict 3\n
+  i>     key1 3\n
+  i>     foo\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
 
 Incomplete value send
 
-  $ hg -R server serve --stdio << EOF
-  > unknown
-  > dict 3
-  > key1 3
-  > fo
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown\n
+  >     dict 3\n
+  >     key1 3\n
+  >     fo
+  > readline
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  0
+  using raw connection to peer
+  i> write(24) -> None:
+  i>     unknown\n
+  i>     dict 3\n
+  i>     key1 3\n
+  i>     fo
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
 
 Send a command line with spaces
 
-  $ hg -R server serve --stdio << EOF
-  > unknown withspace
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown withspace\n
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(18) -> None:
+  i>     unknown withspace\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
-  $ hg -R server serve --stdio << EOF
-  > unknown with multiple spaces
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown with multiple spaces\n
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
   > EOF
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(29) -> None:
+  i>     unknown with multiple spaces\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
 
-  $ hg -R server serve --stdio << EOF
-  > unknown with spaces
-  > key 10
-  > some value
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     unknown with spaces\n
+  >     key 10\n
+  >     some value\n
+  > readline
+  > readline
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
   > EOF
-  0
-  0
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(38) -> None:
+  i>     unknown with spaces\n
+  i>     key 10\n
+  i>     some value\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
 Send an unknown command after the "between"
 
-  $ hg -R server serve --stdio << EOF
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     hello\n
+  > readline
+  > readline
+  > raw
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown
+  > readline
+  > readline
   > EOF
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
-  0
+  using raw connection to peer
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(105) -> None:
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
 
 And one with arguments
 
-  $ hg -R server serve --stdio << EOF
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000unknown
-  > foo 5
-  > value
-  > bar 3
-  > baz
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     hello\n
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
+  > readline
+  > readline
+  > raw
+  >     unknown\n
+  >     foo 5\n
+  >     \nvalue\n
+  >     bar 3\n
+  >     baz\n
+  > readline
+  > readline
+  > readline
   > EOF
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
-  0
-  0
-  0
-  0
-  0
+  using raw connection to peer
+  i> write(104) -> None:
+  i>     hello\n
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  o> readline() -> 2:
+  o>     1\n
+  o> readline() -> 1:
+  o>     \n
+  i> write(31) -> None:
+  i>     unknown\n
+  i>     foo 5\n
+  i>     \n
+  i>     value\n
+  i>     bar 3\n
+  i>     baz\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 2:
+  o>     0\n
+  o> readline() -> 0: 
 
 Send a valid command before the handshake
 
-  $ hg -R server serve --stdio << EOF
-  > heads
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     heads\n
+  > readline
+  > raw
+  >     hello\n
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
+  > readline
+  > readline
   > EOF
-  41
-  68986213bd4485ea51533535e3fc9e78007a711f
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(6) -> None:
+  i>     heads\n
+  o> readline() -> 3:
+  o>     41\n
+  i> write(104) -> None:
+  i>     hello\n
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 41:
+  o>     68986213bd4485ea51533535e3fc9e78007a711f\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  o> readline() -> 2:
+  o>     1\n
 
 And a variation that doesn't send the between command
 
-  $ hg -R server serve --stdio << EOF
-  > heads
-  > hello
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     heads\n
+  > readline
+  > raw
+  >     hello\n
+  > readline
+  > readline
   > EOF
-  41
-  68986213bd4485ea51533535e3fc9e78007a711f
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  using raw connection to peer
+  i> write(6) -> None:
+  i>     heads\n
+  o> readline() -> 3:
+  o>     41\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 41:
+  o>     68986213bd4485ea51533535e3fc9e78007a711f\n
+  o> readline() -> 4:
+  o>     384\n
 
 Send an upgrade request to a server that doesn't support that command
 
-  $ hg -R server serve --stdio << EOF
-  > upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ 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
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(77) -> None:
+  i>     upgrade 2e82ab3f-9ce3-4b4e-8f8c-6fd1c0e9e23a proto=irrelevant1%2Cirrelevant2\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(104) -> None:
+  i>     hello\n
+  i>     between\n
+  i>     pairs 81\n
+  i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\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 * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
@@ -500,17 +950,34 @@ 
 
 Send an upgrade request to a server that supports upgrade
 
-  >>> with open('payload', 'wb') as fh:
-  ...     fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n')
-  ...     fh.write(b'hello\n')
-  ...     fh.write(b'between\n')
-  ...     fh.write(b'pairs 81\n')
-  ...     fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000')
+  $ cd server
 
-  $ hg -R server serve --stdio < payload
-  upgraded this-is-some-token exp-ssh-v2-0001
-  383
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade this-is-some-token proto=exp-ssh-v2-0001\n
+  >     hello\n
+  >     between\n
+  >     pairs 81\n
+  >     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  > readline
+  > readline
+  > readline
+  > EOF
+  using raw connection to peer
+  i> write(153) -> None:
+  i>     upgrade this-is-some-token proto=exp-ssh-v2-0001\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-0001\n
+  o> readline() -> 4:
+  o>     383\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+
+  $ cd ..
 
   $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user@dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
@@ -578,95 +1045,210 @@ 
 
 Command after upgrade to version 2 is processed
 
-  >>> with open('payload', 'wb') as fh:
-  ...     fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n')
-  ...     fh.write(b'hello\n')
-  ...     fh.write(b'between\n')
-  ...     fh.write(b'pairs 81\n')
-  ...     fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000')
-  ...     fh.write(b'hello\n')
-  $ hg -R server serve --stdio < payload
-  upgraded this-is-some-token exp-ssh-v2-0001
-  383
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
+  $ cd server
+
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >      upgrade this-is-some-token proto=exp-ssh-v2-0001\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) -> None:
+  i>     upgrade this-is-some-token proto=exp-ssh-v2-0001\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-0001\n
+  o> readline() -> 4:
+  o>     383\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
 
 Multiple upgrades is not allowed
 
-  >>> with open('payload', 'wb') as fh:
-  ...     fh.write(b'upgrade this-is-some-token proto=exp-ssh-v2-0001\n')
-  ...     fh.write(b'hello\n')
-  ...     fh.write(b'between\n')
-  ...     fh.write(b'pairs 81\n')
-  ...     fh.write(b'0000000000000000000000000000000000000000-0000000000000000000000000000000000000000')
-  ...     fh.write(b'upgrade another-token proto=irrelevant\n')
-  ...     fh.write(b'hello\n')
-  $ hg -R server serve --stdio < payload
-  upgraded this-is-some-token exp-ssh-v2-0001
-  383
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  cannot upgrade protocols multiple times
-  -
-  
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade this-is-some-token proto=exp-ssh-v2-0001\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) -> None:
+  i>     upgrade this-is-some-token proto=exp-ssh-v2-0001\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-0001\n
+  o> readline() -> 4:
+  o>     383\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(45) -> None:
+  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 -R server serve --stdio << EOF
-  > upgrade
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade\n
+  > readline
   > EOF
-  0
+  using raw connection to peer
+  i> write(8) -> None:
+  i>     upgrade\n
+  o> readline() -> 2:
+  o>     0\n
 
-  $ hg -R server serve --stdio << EOF
-  > upgrade token
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade token\n
+  > readline
   > EOF
-  0
+  using raw connection to peer
+  i> write(14) -> None:
+  i>     upgrade token\n
+  o> readline() -> 2:
+  o>     0\n
 
-  $ hg -R server serve --stdio << EOF
-  > upgrade token foo=bar extra-token
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade token foo=bar extra-token\n
+  > readline
   > EOF
-  0
+  using raw connection to peer
+  i> write(34) -> None:
+  i>     upgrade token foo=bar extra-token\n
+  o> readline() -> 2:
+  o>     0\n
 
 Upgrade request to unsupported protocol is ignored
 
-  $ hg -R server serve --stdio << EOF
-  > upgrade this-is-some-token proto=unknown1,unknown2
-  > hello
-  > between
-  > pairs 81
-  > 0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
+  $ 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
-  0
-  384
-  capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN
-  1
-  
+  using raw connection to peer
+  i> write(51) -> None:
+  i>     upgrade this-is-some-token proto=unknown1,unknown2\n
+  o> readline() -> 2:
+  o>     0\n
+  i> write(6) -> None:
+  i>     hello\n
+  o> readline() -> 4:
+  o>     384\n
+  o> readline() -> 384:
+  o>     capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 $USUAL_BUNDLE2_CAPS_SERVER$ unbundle=HG10GZ,HG10BZ,HG10UN\n
+  i> write(98) -> None:
+  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 -R server serve --stdio << EOF
-  > upgrade token proto=exp-ssh-v2-0001
-  > invalid
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade token proto=exp-ssh-v2-0001\n
+  >     invalid\n
+  > readline
+  > readavailable
   > EOF
-  malformed handshake protocol: missing hello
-  -
-  
+  using raw connection to peer
+  i> write(44) -> None:
+  i>     upgrade token proto=exp-ssh-v2-0001\n
+  i>     invalid\n
+  o> readline() -> 1:
+  o>     \n
+  e> read(-1) -> 46:
+  e>     malformed handshake protocol: missing hello\n
+  e>     -\n
 
-  $ hg -R server serve --stdio << EOF
-  > upgrade token proto=exp-ssh-v2-0001
-  > hello
-  > invalid
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade token proto=exp-ssh-v2-0001\n
+  >     hello\n
+  >     invalid\n
+  > readline
+  > readavailable
   > EOF
-  malformed handshake protocol: missing between
-  -
-  
+  using raw connection to peer
+  i> write(50) -> None:
+  i>     upgrade token proto=exp-ssh-v2-0001\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 -R server serve --stdio << EOF
-  > upgrade token proto=exp-ssh-v2-0001
-  > hello
-  > between
-  > invalid
+  $ hg debugwireproto --localssh --peer raw << EOF
+  > raw
+  >     upgrade token proto=exp-ssh-v2-0001\n
+  >     hello\n
+  >     between\n
+  >     invalid\n
+  > readline
+  > readavailable
   > EOF
-  malformed handshake protocol: missing pairs 81
-  -
-  
+  using raw connection to peer
+  i> write(58) -> None:
+  i>     upgrade token proto=exp-ssh-v2-0001\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
diff --git a/tests/test-help.t b/tests/test-help.t
--- a/tests/test-help.t
+++ b/tests/test-help.t
@@ -983,6 +983,8 @@ 
    debugwalk     show how files match on given patterns
    debugwireargs
                  (no help text available)
+   debugwireproto
+                 send wire protocol commands to a server
   
   (use 'hg help -v debug' to show built-in aliases and global options)
 
diff --git a/tests/test-completion.t b/tests/test-completion.t
--- a/tests/test-completion.t
+++ b/tests/test-completion.t
@@ -121,6 +121,7 @@ 
   debugupgraderepo
   debugwalk
   debugwireargs
+  debugwireproto
 
 Do not show the alias of a debug command if there are other candidates
 (this should hide rawcommit)
@@ -302,6 +303,7 @@ 
   debugupgraderepo: optimize, run
   debugwalk: include, exclude
   debugwireargs: three, four, five, ssh, remotecmd, insecure
+  debugwireproto: localssh, peer, ssh, remotecmd, insecure
   files: rev, print0, include, exclude, template, subrepos
   graft: rev, continue, edit, log, force, currentdate, currentuser, date, user, tool, dry-run
   grep: print0, all, text, follow, ignore-case, files-with-matches, line-number, rev, user, date, template, include, exclude
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -17,6 +17,7 @@ 
 import socket
 import ssl
 import string
+import subprocess
 import sys
 import tempfile
 import time
@@ -65,6 +66,7 @@ 
     setdiscovery,
     simplemerge,
     smartset,
+    sshpeer,
     sslutil,
     streamclone,
     templater,
@@ -2528,3 +2530,204 @@ 
     ui.write("%s\n" % res1)
     if res1 != res2:
         ui.warn("%s\n" % res2)
+
+def _parsewirelangblocks(fh):
+    activeaction = None
+    blocklines = []
+
+    for line in fh:
+        line = line.rstrip()
+        if not line:
+            continue
+
+        if line.startswith(b'#'):
+            continue
+
+        if not line.startswith(' '):
+            # New block. Flush previous one.
+            if activeaction:
+                yield activeaction, blocklines
+
+            activeaction = line
+            blocklines = []
+            continue
+
+        # Else we start with an indent.
+
+        if not activeaction:
+            raise error.Abort(_('indented line outside of block'))
+
+        blocklines.append(line)
+
+    # Flush last block.
+    if activeaction:
+        yield activeaction, blocklines
+
+@command('debugwireproto',
+    [
+        ('', 'localssh', False, _('start an SSH server for this repo')),
+        ('', 'peer', '', _('construct a specific version of the peer')),
+    ] + cmdutil.remoteopts,
+    _('[REPO]'),
+    optionalrepo=True)
+def debugwireproto(ui, repo, **opts):
+    """send wire protocol commands to a server
+
+    This command can be used to issue wire protocol commands to remote
+    peers and to debug the raw data being exchanged.
+
+    ``--localssh`` will start an SSH server against the current repository
+    and connect to that. By default, the connection will perform a handshake
+    and establish an appropriate peer instance.
+
+    ``--peer`` can be used to bypass the handshake protocol and construct a
+    peer instance using the specified class type. Valid values are ``raw``,
+    ``ssh1``, and ``ssh2``. ``raw`` instances only allow sending raw data
+    payloads and don't support higher-level command actions.
+
+    Commands are issued via a mini language which is specified via stdin.
+    The language consists of individual actions to perform. An action is
+    defined by a block. A block is defined as a line with no leading
+    space followed by 0 or more lines with leading space. Blocks are
+    effectively a high-level command with additional metadata.
+
+    Lines beginning with ``#`` are ignored.
+
+    The following sections denote available actions.
+
+    raw
+    ---
+
+    Send raw data to the server.
+
+    The block payload contains the raw data to send as one atomic send
+    operation. The data may not actually be delivered in a single system
+    call: it depends on the abilities of the transport being used.
+
+    Each line in the block is de-indented and concatenated. Then, that
+    value is evaluated as a Python b'' literal. This allows the use of
+    backslash escaping, etc.
+
+    raw+
+    ----
+
+    Behaves like ``raw`` except flushes output afterwards.
+
+    close
+    -----
+
+    Close the connection to the server.
+
+    flush
+    -----
+
+    Flush data written to the server.
+
+    readavailable
+    -------------
+
+    Read all available data from the server.
+
+    If the connection to the server encompasses multiple pipes, we poll both
+    pipes and read available data.
+
+    readline
+    --------
+
+    Read a line of output from the server. If there are multiple output
+    pipes, reads only the main pipe.
+    """
+    opts = pycompat.byteskwargs(opts)
+
+    if opts['localssh'] and not repo:
+        raise error.Abort(_('--localssh requires a repository'))
+
+    if opts['peer'] and opts['peer'] not in ('raw', 'ssh1', 'ssh2'):
+        raise error.Abort(_('invalid value for --peer'),
+                          hint=_('valid values are "raw", "ssh1", and "ssh2"'))
+
+    if ui.interactive():
+        ui.write(_('(waiting for commands on stdin)\n'))
+
+    blocks = list(_parsewirelangblocks(ui.fin))
+
+    proc = None
+
+    if opts['localssh']:
+        # We start the SSH server in its own process so there is process
+        # separation. This prevents a whole class of potential bugs around
+        # shared state from interfering with server operation.
+        args = util.hgcmd() + [
+            '-R', repo.root,
+            'debugserve', '--sshstdio',
+        ]
+        proc = subprocess.Popen(args, stdin=subprocess.PIPE,
+                                stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+                                bufsize=0)
+
+        stdin = proc.stdin
+        stdout = proc.stdout
+        stderr = proc.stderr
+
+        # We turn the pipes into observers so we can log I/O.
+        if ui.verbose or opts['peer'] == 'raw':
+            stdin = util.makeloggingfileobject(ui, proc.stdin, b'i',
+                                               logdata=True)
+            stdout = util.makeloggingfileobject(ui, proc.stdout, b'o',
+                                                logdata=True)
+            stderr = util.makeloggingfileobject(ui, proc.stderr, b'e',
+                                                logdata=True)
+
+        # --localssh also implies the peer connection settings.
+
+        url = 'ssh://localserver'
+
+        if opts['peer'] == 'ssh1':
+            ui.write(_('creating ssh peer for wire protocol version 1\n'))
+            peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr,
+                                     None)
+        elif opts['peer'] == 'ssh2':
+            ui.write(_('creating ssh peer for wire protocol version 2\n'))
+            peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr,
+                                     None)
+        elif opts['peer'] == 'raw':
+            ui.write(_('using raw connection to peer\n'))
+            peer = None
+        else:
+            ui.write(_('creating ssh peer from handshake results\n'))
+            peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr)
+
+    else:
+        raise error.Abort(_('only --localssh is currently supported'))
+
+    # Now perform actions based on the parsed wire language instructions.
+    for action, lines in blocks:
+        if action in ('raw', 'raw+'):
+            # Concatenate the data together.
+            data = ''.join(l.lstrip() for l in lines)
+            data = util.unescapestr(data)
+            stdin.write(data)
+
+            if action == 'raw+':
+                stdin.flush()
+        elif action == 'flush':
+            stdin.flush()
+        elif action == 'close':
+            peer.close()
+        elif action == 'readavailable':
+            fds = util.poll([stdout.fileno(), stderr.fileno()])
+
+            if stdout.fileno() in fds:
+                util.readpipe(stdout)
+            if stderr.fileno() in fds:
+                util.readpipe(stderr)
+        elif action == 'readline':
+            stdout.readline()
+        else:
+            raise error.Abort(_('unknown action: %s') % action)
+
+    if peer:
+        peer.close()
+
+    if proc:
+        proc.kill()