diff tests/test-bundle2-format.t @ 23048:ee5f834077be stable

merge default into stable for 3.2 freeze
author Matt Mackall <mpm@selenic.com>
date Sat, 18 Oct 2014 18:04:31 -0500
parents 90f86ad3d4ff
children 420a051616ce
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-bundle2-format.t	Sat Oct 18 18:04:31 2014 -0500
@@ -0,0 +1,802 @@
+This test is decicated to test the bundle2 container format
+
+It test multiple existing parts to test different feature of the container. You
+probably do not need to touch this test unless you change the binary encoding
+of the bundle2 format itself.
+
+Create an extension to test bundle2 API
+
+  $ cat > bundle2.py << EOF
+  > """A small extension to test bundle2 implementation
+  > 
+  > Current bundle2 implementation is far too limited to be used in any core
+  > code. We still need to be able to test it while it grow up.
+  > """
+  > 
+  > import sys, os
+  > from mercurial import cmdutil
+  > from mercurial import util
+  > from mercurial import bundle2
+  > from mercurial import scmutil
+  > from mercurial import discovery
+  > from mercurial import changegroup
+  > from mercurial import error
+  > from mercurial import obsolete
+  > 
+  > 
+  > try:
+  >     import msvcrt
+  >     msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
+  >     msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
+  >     msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
+  > except ImportError:
+  >     pass
+  > 
+  > cmdtable = {}
+  > command = cmdutil.command(cmdtable)
+  > 
+  > ELEPHANTSSONG = """Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+  > Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+  > Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko."""
+  > assert len(ELEPHANTSSONG) == 178 # future test say 178 bytes, trust it.
+  > 
+  > @bundle2.parthandler('test:song')
+  > def songhandler(op, part):
+  >     """handle a "test:song" bundle2 part, printing the lyrics on stdin"""
+  >     op.ui.write('The choir starts singing:\n')
+  >     verses = 0
+  >     for line in part.read().split('\n'):
+  >         op.ui.write('    %s\n' % line)
+  >         verses += 1
+  >     op.records.add('song', {'verses': verses})
+  > 
+  > @bundle2.parthandler('test:ping')
+  > def pinghandler(op, part):
+  >     op.ui.write('received ping request (id %i)\n' % part.id)
+  >     if op.reply is not None and 'ping-pong' in op.reply.capabilities:
+  >         op.ui.write_err('replying to ping request (id %i)\n' % part.id)
+  >         op.reply.newpart('test:pong', [('in-reply-to', str(part.id))])
+  > 
+  > @bundle2.parthandler('test:debugreply')
+  > def debugreply(op, part):
+  >     """print data about the capacity of the bundle reply"""
+  >     if op.reply is None:
+  >         op.ui.write('debugreply: no reply\n')
+  >     else:
+  >         op.ui.write('debugreply: capabilities:\n')
+  >         for cap in sorted(op.reply.capabilities):
+  >             op.ui.write('debugreply:     %r\n' % cap)
+  >             for val in op.reply.capabilities[cap]:
+  >                 op.ui.write('debugreply:         %r\n' % val)
+  > 
+  > @command('bundle2',
+  >          [('', 'param', [], 'stream level parameter'),
+  >           ('', 'unknown', False, 'include an unknown mandatory part in the bundle'),
+  >           ('', 'unknownparams', False, 'include an unknown part parameters in the bundle'),
+  >           ('', 'parts', False, 'include some arbitrary parts to the bundle'),
+  >           ('', 'reply', False, 'produce a reply bundle'),
+  >           ('', 'pushrace', False, 'includes a check:head part with unknown nodes'),
+  >           ('', 'genraise', False, 'includes a part that raise an exception during generation'),
+  >           ('r', 'rev', [], 'includes those changeset in the bundle'),],
+  >          '[OUTPUTFILE]')
+  > def cmdbundle2(ui, repo, path=None, **opts):
+  >     """write a bundle2 container on standard ouput"""
+  >     bundler = bundle2.bundle20(ui)
+  >     for p in opts['param']:
+  >         p = p.split('=', 1)
+  >         try:
+  >             bundler.addparam(*p)
+  >         except ValueError, exc:
+  >             raise util.Abort('%s' % exc)
+  > 
+  >     if opts['reply']:
+  >         capsstring = 'ping-pong\nelephants=babar,celeste\ncity%3D%21=celeste%2Cville'
+  >         bundler.newpart('b2x:replycaps', data=capsstring)
+  > 
+  >     if opts['pushrace']:
+  >         # also serve to test the assignement of data outside of init
+  >         part = bundler.newpart('b2x:check:heads')
+  >         part.data = '01234567890123456789'
+  > 
+  >     revs = opts['rev']
+  >     if 'rev' in opts:
+  >         revs = scmutil.revrange(repo, opts['rev'])
+  >         if revs:
+  >             # very crude version of a changegroup part creation
+  >             bundled = repo.revs('%ld::%ld', revs, revs)
+  >             headmissing = [c.node() for c in repo.set('heads(%ld)', revs)]
+  >             headcommon  = [c.node() for c in repo.set('parents(%ld) - %ld', revs, revs)]
+  >             outgoing = discovery.outgoing(repo.changelog, headcommon, headmissing)
+  >             cg = changegroup.getlocalchangegroup(repo, 'test:bundle2', outgoing, None)
+  >             bundler.newpart('b2x:changegroup', data=cg.getchunks())
+  > 
+  >     if opts['parts']:
+  >        bundler.newpart('test:empty')
+  >        # add a second one to make sure we handle multiple parts
+  >        bundler.newpart('test:empty')
+  >        bundler.newpart('test:song', data=ELEPHANTSSONG)
+  >        bundler.newpart('test:debugreply')
+  >        mathpart = bundler.newpart('test:math')
+  >        mathpart.addparam('pi', '3.14')
+  >        mathpart.addparam('e', '2.72')
+  >        mathpart.addparam('cooking', 'raw', mandatory=False)
+  >        mathpart.data = '42'
+  >        # advisory known part with unknown mandatory param
+  >        bundler.newpart('test:song', [('randomparam','')])
+  >     if opts['unknown']:
+  >        bundler.newpart('test:UNKNOWN', data='some random content')
+  >     if opts['unknownparams']:
+  >        bundler.newpart('test:SONG', [('randomparams', '')])
+  >     if opts['parts']:
+  >        bundler.newpart('test:ping')
+  >     if opts['genraise']:
+  >        def genraise():
+  >            yield 'first line\n'
+  >            raise RuntimeError('Someone set up us the bomb!')
+  >        bundler.newpart('b2x:output', data=genraise())
+  > 
+  >     if path is None:
+  >        file = sys.stdout
+  >     else:
+  >         file = open(path, 'wb')
+  > 
+  >     try:
+  >         for chunk in bundler.getchunks():
+  >             file.write(chunk)
+  >     except RuntimeError, exc:
+  >         raise util.Abort(exc)
+  > 
+  > @command('unbundle2', [], '')
+  > def cmdunbundle2(ui, repo, replypath=None):
+  >     """process a bundle2 stream from stdin on the current repo"""
+  >     try:
+  >         tr = None
+  >         lock = repo.lock()
+  >         tr = repo.transaction('processbundle')
+  >         try:
+  >             unbundler = bundle2.unbundle20(ui, sys.stdin)
+  >             op = bundle2.processbundle(repo, unbundler, lambda: tr)
+  >             tr.close()
+  >         except error.BundleValueError, exc:
+  >             raise util.Abort('missing support for %s' % exc)
+  >         except error.PushRaced, exc:
+  >             raise util.Abort('push race: %s' % exc)
+  >     finally:
+  >         if tr is not None:
+  >             tr.release()
+  >         lock.release()
+  >         remains = sys.stdin.read()
+  >         ui.write('%i unread bytes\n' % len(remains))
+  >     if op.records['song']:
+  >         totalverses = sum(r['verses'] for r in op.records['song'])
+  >         ui.write('%i total verses sung\n' % totalverses)
+  >     for rec in op.records['changegroup']:
+  >         ui.write('addchangegroup return: %i\n' % rec['return'])
+  >     if op.reply is not None and replypath is not None:
+  >         file = open(replypath, 'wb')
+  >         for chunk in op.reply.getchunks():
+  >             file.write(chunk)
+  > 
+  > @command('statbundle2', [], '')
+  > def cmdstatbundle2(ui, repo):
+  >     """print statistic on the bundle2 container read from stdin"""
+  >     unbundler = bundle2.unbundle20(ui, sys.stdin)
+  >     try:
+  >         params = unbundler.params
+  >     except error.BundleValueError, exc:
+  >        raise util.Abort('unknown parameters: %s' % exc)
+  >     ui.write('options count: %i\n' % len(params))
+  >     for key in sorted(params):
+  >         ui.write('- %s\n' % key)
+  >         value = params[key]
+  >         if value is not None:
+  >             ui.write('    %s\n' % value)
+  >     count = 0
+  >     for p in unbundler.iterparts():
+  >         count += 1
+  >         ui.write('  :%s:\n' % p.type)
+  >         ui.write('    mandatory: %i\n' % len(p.mandatoryparams))
+  >         ui.write('    advisory: %i\n' % len(p.advisoryparams))
+  >         ui.write('    payload: %i bytes\n' % len(p.read()))
+  >     ui.write('parts count:   %i\n' % count)
+  > EOF
+  $ cat >> $HGRCPATH << EOF
+  > [extensions]
+  > bundle2=$TESTTMP/bundle2.py
+  > [experimental]
+  > bundle2-exp=True
+  > evolution=createmarkers
+  > [ui]
+  > ssh=python "$TESTDIR/dummyssh"
+  > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
+  > [web]
+  > push_ssl = false
+  > allow_push = *
+  > [phases]
+  > publish=False
+  > EOF
+
+The extension requires a repo (currently unused)
+
+  $ hg init main
+  $ cd main
+  $ touch a
+  $ hg add a
+  $ hg commit -m 'a'
+
+
+Empty bundle
+=================
+
+- no option
+- no parts
+
+Test bundling
+
+  $ hg bundle2
+  HG2Y\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
+
+Test unbundling
+
+  $ hg bundle2 | hg statbundle2
+  options count: 0
+  parts count:   0
+
+Test old style bundle are detected and refused
+
+  $ hg bundle --all ../bundle.hg
+  1 changesets found
+  $ hg statbundle2 < ../bundle.hg
+  abort: unknown bundle version 10
+  [255]
+
+Test parameters
+=================
+
+- some options
+- no parts
+
+advisory parameters, no value
+-------------------------------
+
+Simplest possible parameters form
+
+Test generation simple option
+
+  $ hg bundle2 --param 'caution'
+  HG2Y\x00\x00\x00\x07caution\x00\x00\x00\x00 (no-eol) (esc)
+
+Test unbundling
+
+  $ hg bundle2 --param 'caution' | hg statbundle2
+  options count: 1
+  - caution
+  parts count:   0
+
+Test generation multiple option
+
+  $ hg bundle2 --param 'caution' --param 'meal'
+  HG2Y\x00\x00\x00\x0ccaution meal\x00\x00\x00\x00 (no-eol) (esc)
+
+Test unbundling
+
+  $ hg bundle2 --param 'caution' --param 'meal' | hg statbundle2
+  options count: 2
+  - caution
+  - meal
+  parts count:   0
+
+advisory parameters, with value
+-------------------------------
+
+Test generation
+
+  $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants'
+  HG2Y\x00\x00\x00\x1ccaution meal=vegan elephants\x00\x00\x00\x00 (no-eol) (esc)
+
+Test unbundling
+
+  $ hg bundle2 --param 'caution' --param 'meal=vegan' --param 'elephants' | hg statbundle2
+  options count: 3
+  - caution
+  - elephants
+  - meal
+      vegan
+  parts count:   0
+
+parameter with special char in value
+---------------------------------------------------
+
+Test generation
+
+  $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple
+  HG2Y\x00\x00\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00\x00\x00 (no-eol) (esc)
+
+Test unbundling
+
+  $ hg bundle2 --param 'e|! 7/=babar%#==tutu' --param simple | hg statbundle2
+  options count: 2
+  - e|! 7/
+      babar%#==tutu
+  - simple
+  parts count:   0
+
+Test unknown mandatory option
+---------------------------------------------------
+
+  $ hg bundle2 --param 'Gravity' | hg statbundle2
+  abort: unknown parameters: Stream Parameter - Gravity
+  [255]
+
+Test debug output
+---------------------------------------------------
+
+bundling debug
+
+  $ hg bundle2 --debug --param 'e|! 7/=babar%#==tutu' --param simple ../out.hg2
+  start emission of HG2Y stream
+  bundle parameter: e%7C%21%207/=babar%25%23%3D%3Dtutu simple
+  start of parts
+  end of bundle
+
+file content is ok
+
+  $ cat ../out.hg2
+  HG2Y\x00\x00\x00)e%7C%21%207/=babar%25%23%3D%3Dtutu simple\x00\x00\x00\x00 (no-eol) (esc)
+
+unbundling debug
+
+  $ hg statbundle2 --debug < ../out.hg2
+  start processing of HG2Y stream
+  reading bundle2 stream parameters
+  ignoring unknown parameter 'e|! 7/'
+  ignoring unknown parameter 'simple'
+  options count: 2
+  - e|! 7/
+      babar%#==tutu
+  - simple
+  start extraction of bundle2 parts
+  part header size: 0
+  end of bundle2 stream
+  parts count:   0
+
+
+Test buggy input
+---------------------------------------------------
+
+empty parameter name
+
+  $ hg bundle2 --param '' --quiet
+  abort: empty parameter name
+  [255]
+
+bad parameter name
+
+  $ hg bundle2 --param 42babar
+  abort: non letter first character: '42babar'
+  [255]
+
+
+Test part
+=================
+
+  $ hg bundle2 --parts ../parts.hg2 --debug
+  start emission of HG2Y stream
+  bundle parameter: 
+  start of parts
+  bundle part: "test:empty"
+  bundle part: "test:empty"
+  bundle part: "test:song"
+  bundle part: "test:debugreply"
+  bundle part: "test:math"
+  bundle part: "test:song"
+  bundle part: "test:ping"
+  end of bundle
+
+  $ cat ../parts.hg2
+  HG2Y\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
+  test:empty\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
+  test:empty\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10	test:song\x00\x00\x00\x02\x00\x00\x00\x00\x00\xb2Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko (esc)
+  Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+  Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.\x00\x00\x00\x00\x00\x00\x00\x16\x0ftest:debugreply\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00+	test:math\x00\x00\x00\x04\x02\x01\x02\x04\x01\x04\x07\x03pi3.14e2.72cookingraw\x00\x00\x00\x0242\x00\x00\x00\x00\x00\x00\x00\x1d	test:song\x00\x00\x00\x05\x01\x00\x0b\x00randomparam\x00\x00\x00\x00\x00\x00\x00\x10	test:ping\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
+
+
+  $ hg statbundle2 < ../parts.hg2
+  options count: 0
+    :test:empty:
+      mandatory: 0
+      advisory: 0
+      payload: 0 bytes
+    :test:empty:
+      mandatory: 0
+      advisory: 0
+      payload: 0 bytes
+    :test:song:
+      mandatory: 0
+      advisory: 0
+      payload: 178 bytes
+    :test:debugreply:
+      mandatory: 0
+      advisory: 0
+      payload: 0 bytes
+    :test:math:
+      mandatory: 2
+      advisory: 1
+      payload: 2 bytes
+    :test:song:
+      mandatory: 1
+      advisory: 0
+      payload: 0 bytes
+    :test:ping:
+      mandatory: 0
+      advisory: 0
+      payload: 0 bytes
+  parts count:   7
+
+  $ hg statbundle2 --debug < ../parts.hg2
+  start processing of HG2Y stream
+  reading bundle2 stream parameters
+  options count: 0
+  start extraction of bundle2 parts
+  part header size: 17
+  part type: "test:empty"
+  part id: "0"
+  part parameters: 0
+    :test:empty:
+      mandatory: 0
+      advisory: 0
+  payload chunk size: 0
+      payload: 0 bytes
+  part header size: 17
+  part type: "test:empty"
+  part id: "1"
+  part parameters: 0
+    :test:empty:
+      mandatory: 0
+      advisory: 0
+  payload chunk size: 0
+      payload: 0 bytes
+  part header size: 16
+  part type: "test:song"
+  part id: "2"
+  part parameters: 0
+    :test:song:
+      mandatory: 0
+      advisory: 0
+  payload chunk size: 178
+  payload chunk size: 0
+      payload: 178 bytes
+  part header size: 22
+  part type: "test:debugreply"
+  part id: "3"
+  part parameters: 0
+    :test:debugreply:
+      mandatory: 0
+      advisory: 0
+  payload chunk size: 0
+      payload: 0 bytes
+  part header size: 43
+  part type: "test:math"
+  part id: "4"
+  part parameters: 3
+    :test:math:
+      mandatory: 2
+      advisory: 1
+  payload chunk size: 2
+  payload chunk size: 0
+      payload: 2 bytes
+  part header size: 29
+  part type: "test:song"
+  part id: "5"
+  part parameters: 1
+    :test:song:
+      mandatory: 1
+      advisory: 0
+  payload chunk size: 0
+      payload: 0 bytes
+  part header size: 16
+  part type: "test:ping"
+  part id: "6"
+  part parameters: 0
+    :test:ping:
+      mandatory: 0
+      advisory: 0
+  payload chunk size: 0
+      payload: 0 bytes
+  part header size: 0
+  end of bundle2 stream
+  parts count:   7
+
+Test actual unbundling of test part
+=======================================
+
+Process the bundle
+
+  $ hg unbundle2 --debug < ../parts.hg2
+  start processing of HG2Y stream
+  reading bundle2 stream parameters
+  start extraction of bundle2 parts
+  part header size: 17
+  part type: "test:empty"
+  part id: "0"
+  part parameters: 0
+  ignoring unsupported advisory part test:empty
+  payload chunk size: 0
+  part header size: 17
+  part type: "test:empty"
+  part id: "1"
+  part parameters: 0
+  ignoring unsupported advisory part test:empty
+  payload chunk size: 0
+  part header size: 16
+  part type: "test:song"
+  part id: "2"
+  part parameters: 0
+  found a handler for part 'test:song'
+  The choir starts singing:
+  payload chunk size: 178
+  payload chunk size: 0
+      Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+      Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+      Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
+  part header size: 22
+  part type: "test:debugreply"
+  part id: "3"
+  part parameters: 0
+  found a handler for part 'test:debugreply'
+  debugreply: no reply
+  payload chunk size: 0
+  part header size: 43
+  part type: "test:math"
+  part id: "4"
+  part parameters: 3
+  ignoring unsupported advisory part test:math
+  payload chunk size: 2
+  payload chunk size: 0
+  part header size: 29
+  part type: "test:song"
+  part id: "5"
+  part parameters: 1
+  found a handler for part 'test:song'
+  ignoring unsupported advisory part test:song - randomparam
+  payload chunk size: 0
+  part header size: 16
+  part type: "test:ping"
+  part id: "6"
+  part parameters: 0
+  found a handler for part 'test:ping'
+  received ping request (id 6)
+  payload chunk size: 0
+  part header size: 0
+  end of bundle2 stream
+  0 unread bytes
+  3 total verses sung
+
+Unbundle with an unknown mandatory part
+(should abort)
+
+  $ hg bundle2 --parts --unknown ../unknown.hg2
+
+  $ hg unbundle2 < ../unknown.hg2
+  The choir starts singing:
+      Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+      Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+      Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
+  debugreply: no reply
+  0 unread bytes
+  abort: missing support for test:unknown
+  [255]
+
+Unbundle with an unknown mandatory part parameters
+(should abort)
+
+  $ hg bundle2 --unknownparams ../unknown.hg2
+
+  $ hg unbundle2 < ../unknown.hg2
+  0 unread bytes
+  abort: missing support for test:song - randomparams
+  [255]
+
+unbundle with a reply
+
+  $ hg bundle2 --parts --reply ../parts-reply.hg2
+  $ hg unbundle2 ../reply.hg2 < ../parts-reply.hg2
+  0 unread bytes
+  3 total verses sung
+
+The reply is a bundle
+
+  $ cat ../reply.hg2
+  HG2Y\x00\x00\x00\x00\x00\x00\x00\x1f (esc)
+  b2x:output\x00\x00\x00\x00\x00\x01\x0b\x01in-reply-to3\x00\x00\x00\xd9The choir starts singing: (esc)
+      Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+      Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+      Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
+  \x00\x00\x00\x00\x00\x00\x00\x1f (esc)
+  b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to4\x00\x00\x00\xc9debugreply: capabilities: (esc)
+  debugreply:     'city=!'
+  debugreply:         'celeste,ville'
+  debugreply:     'elephants'
+  debugreply:         'babar'
+  debugreply:         'celeste'
+  debugreply:     'ping-pong'
+  \x00\x00\x00\x00\x00\x00\x00\x1e	test:pong\x00\x00\x00\x02\x01\x00\x0b\x01in-reply-to7\x00\x00\x00\x00\x00\x00\x00\x1f (esc)
+  b2x:output\x00\x00\x00\x03\x00\x01\x0b\x01in-reply-to7\x00\x00\x00=received ping request (id 7) (esc)
+  replying to ping request (id 7)
+  \x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
+
+The reply is valid
+
+  $ hg statbundle2 < ../reply.hg2
+  options count: 0
+    :b2x:output:
+      mandatory: 0
+      advisory: 1
+      payload: 217 bytes
+    :b2x:output:
+      mandatory: 0
+      advisory: 1
+      payload: 201 bytes
+    :test:pong:
+      mandatory: 1
+      advisory: 0
+      payload: 0 bytes
+    :b2x:output:
+      mandatory: 0
+      advisory: 1
+      payload: 61 bytes
+  parts count:   4
+
+Unbundle the reply to get the output:
+
+  $ hg unbundle2 < ../reply.hg2
+  remote: The choir starts singing:
+  remote:     Patali Dirapata, Cromda Cromda Ripalo, Pata Pata, Ko Ko Ko
+  remote:     Bokoro Dipoulito, Rondi Rondi Pepino, Pata Pata, Ko Ko Ko
+  remote:     Emana Karassoli, Loucra Loucra Ponponto, Pata Pata, Ko Ko Ko.
+  remote: debugreply: capabilities:
+  remote: debugreply:     'city=!'
+  remote: debugreply:         'celeste,ville'
+  remote: debugreply:     'elephants'
+  remote: debugreply:         'babar'
+  remote: debugreply:         'celeste'
+  remote: debugreply:     'ping-pong'
+  remote: received ping request (id 7)
+  remote: replying to ping request (id 7)
+  0 unread bytes
+
+Test push race detection
+
+  $ hg bundle2 --pushrace ../part-race.hg2
+
+  $ hg unbundle2 < ../part-race.hg2
+  0 unread bytes
+  abort: push race: repository changed while pushing - please try again
+  [255]
+
+Support for changegroup
+===================================
+
+  $ hg unbundle $TESTDIR/bundles/rebase.hg
+  adding changesets
+  adding manifests
+  adding file changes
+  added 8 changesets with 7 changes to 7 files (+3 heads)
+  (run 'hg heads' to see heads, 'hg merge' to merge)
+
+  $ hg log -G
+  o  8:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com>  H
+  |
+  | o  7:eea13746799a draft Nicolas Dumazet <nicdumz.commits@gmail.com>  G
+  |/|
+  o |  6:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com>  F
+  | |
+  | o  5:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com>  E
+  |/
+  | o  4:32af7686d403 draft Nicolas Dumazet <nicdumz.commits@gmail.com>  D
+  | |
+  | o  3:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com>  C
+  | |
+  | o  2:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com>  B
+  |/
+  o  1:cd010b8cd998 draft Nicolas Dumazet <nicdumz.commits@gmail.com>  A
+  
+  @  0:3903775176ed draft test  a
+  
+
+  $ hg bundle2 --debug --rev '8+7+5+4' ../rev.hg2
+  4 changesets found
+  list of changesets:
+  32af7686d403cf45b5d95f2d70cebea587ac806a
+  9520eea781bcca16c1e15acc0ba14335a0e8e5ba
+  eea13746799a9e0bfd88f29d3c2e9dc9389f524f
+  02de42196ebee42ef284b6780a87cdc96e8eaab6
+  start emission of HG2Y stream
+  bundle parameter: 
+  start of parts
+  bundle part: "b2x:changegroup"
+  bundling: 1/4 changesets (25.00%)
+  bundling: 2/4 changesets (50.00%)
+  bundling: 3/4 changesets (75.00%)
+  bundling: 4/4 changesets (100.00%)
+  bundling: 1/4 manifests (25.00%)
+  bundling: 2/4 manifests (50.00%)
+  bundling: 3/4 manifests (75.00%)
+  bundling: 4/4 manifests (100.00%)
+  bundling: D 1/3 files (33.33%)
+  bundling: E 2/3 files (66.67%)
+  bundling: H 3/3 files (100.00%)
+  end of bundle
+
+  $ cat ../rev.hg2
+  HG2Y\x00\x00\x00\x00\x00\x00\x00\x16\x0fb2x:changegroup\x00\x00\x00\x00\x00\x00\x00\x00\x06\x13\x00\x00\x00\xa42\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j_\xdd\xd9\x89W\xc8\xa5JMCm\xfe\x1d\xa9\xd8\x7f!\xa1\xb9{\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)6e1f4c47ecb533ffd0c8e52cdc88afb6cd39e20c (esc)
+  \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02D (esc)
+  \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01D\x00\x00\x00\xa4\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xcd\x01\x0b\x8c\xd9\x98\xf3\x98\x1aZ\x81\x15\xf9O\x8d\xa4\xabP`\x89\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)4dece9c826f69490507b98c6383a3009b295837d (esc)
+  \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x02E (esc)
+  \x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01E\x00\x00\x00\xa2\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)365b93d57fdf4814e2b5911d6bacff2b12014441 (esc)
+  \x00\x00\x00f\x00\x00\x00h\x00\x00\x00\x00\x00\x00\x00i\x00\x00\x00j\x00\x00\x00\x01G\x00\x00\x00\xa4\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
+  \x87\xcd\xc9n\x8e\xaa\xb6$\xb68|\x8c\x8c\xae7\x17\x88\x80\xf3\xfa\x95\xde\xd3\xcb\x1c\xf7\x85\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
+  \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00)8bee48edc7318541fc0013ee41b089276a8c24bf (esc)
+  \x00\x00\x00f\x00\x00\x00f\x00\x00\x00\x02H (esc)
+  \x00\x00\x00g\x00\x00\x00h\x00\x00\x00\x01H\x00\x00\x00\x00\x00\x00\x00\x8bn\x1fLG\xec\xb53\xff\xd0\xc8\xe5,\xdc\x88\xaf\xb6\xcd9\xe2\x0cf\xa5\xa0\x18\x17\xfd\xf5#\x9c'8\x02\xb5\xb7a\x8d\x05\x1c\x89\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+D\x00c3f1ca2924c16a19b0656a84900e504e5b0aec2d (esc)
+  \x00\x00\x00\x8bM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0	\xb2\x95\x83}\x00}\x8c\x9d\x88\x84\x13%\xf5\xc6\xb0cq\xb3[N\x8a+\x1a\x83\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00+\x00\x00\x00\xac\x00\x00\x00+E\x009c6fd0350a6c0d0c49d4a9c5017cf07043f54e58 (esc)
+  \x00\x00\x00\x8b6[\x93\xd5\x7f\xdfH\x14\xe2\xb5\x91\x1dk\xac\xff+\x12\x01DA(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xceM\xec\xe9\xc8&\xf6\x94\x90P{\x98\xc68:0	\xb2\x95\x83}\xee\xa17Fy\x9a\x9e\x0b\xfd\x88\xf2\x9d<.\x9d\xc98\x9fRO\x00\x00\x00V\x00\x00\x00V\x00\x00\x00+F\x0022bfcfd62a21a3287edbd4d656218d0f525ed76a (esc)
+  \x00\x00\x00\x97\x8b\xeeH\xed\xc71\x85A\xfc\x00\x13\xeeA\xb0\x89'j\x8c$\xbf(\xa5\x84\xc6^\xf1!\xf8\x9e\xb6j\xb7\xd0\xbc\x15=\x80\x99\xe7\xce\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
+  \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00+\x00\x00\x00V\x00\x00\x00\x00\x00\x00\x00\x81\x00\x00\x00\x81\x00\x00\x00+H\x008500189e74a9e0475e822093bc7db0d631aeb0b4 (esc)
+  \x00\x00\x00\x00\x00\x00\x00\x05D\x00\x00\x00b\xc3\xf1\xca)$\xc1j\x19\xb0ej\x84\x90\x0ePN[ (esc)
+  \xec-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x002\xafv\x86\xd4\x03\xcfE\xb5\xd9_-p\xce\xbe\xa5\x87\xac\x80j\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02D (esc)
+  \x00\x00\x00\x00\x00\x00\x00\x05E\x00\x00\x00b\x9co\xd05 (esc)
+  l\r (no-eol) (esc)
+  \x0cI\xd4\xa9\xc5\x01|\xf0pC\xf5NX\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x95 \xee\xa7\x81\xbc\xca\x16\xc1\xe1Z\xcc\x0b\xa1C5\xa0\xe8\xe5\xba\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02E (esc)
+  \x00\x00\x00\x00\x00\x00\x00\x05H\x00\x00\x00b\x85\x00\x18\x9et\xa9\xe0G^\x82 \x93\xbc}\xb0\xd61\xae\xb0\xb4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xdeB\x19n\xbe\xe4.\xf2\x84\xb6x (esc)
+  \x87\xcd\xc9n\x8e\xaa\xb6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02H (esc)
+  \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
+
+  $ hg unbundle2 < ../rev.hg2
+  adding changesets
+  adding manifests
+  adding file changes
+  added 0 changesets with 0 changes to 3 files
+  0 unread bytes
+  addchangegroup return: 1
+
+with reply
+
+  $ hg bundle2 --rev '8+7+5+4' --reply ../rev-rr.hg2
+  $ hg unbundle2 ../rev-reply.hg2 < ../rev-rr.hg2
+  0 unread bytes
+  addchangegroup return: 1
+
+  $ cat ../rev-reply.hg2
+  HG2Y\x00\x00\x00\x00\x00\x00\x003\x15b2x:reply:changegroup\x00\x00\x00\x00\x00\x02\x0b\x01\x06\x01in-reply-to1return1\x00\x00\x00\x00\x00\x00\x00\x1f (esc)
+  b2x:output\x00\x00\x00\x01\x00\x01\x0b\x01in-reply-to1\x00\x00\x00dadding changesets (esc)
+  adding manifests
+  adding file changes
+  added 0 changesets with 0 changes to 3 files
+  \x00\x00\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
+
+Check handling of exception during generation.
+----------------------------------------------
+(is currently not right)
+
+  $ hg bundle2 --genraise > ../genfailed.hg2
+  abort: Someone set up us the bomb!
+  [255]
+
+Should still be a valid bundle
+(is currently not right)
+
+  $ cat ../genfailed.hg2
+  HG2Y\x00\x00\x00\x00\x00\x00\x00\x11 (esc)
+  b2x:output\x00\x00\x00\x00\x00\x00 (no-eol) (esc)
+
+And its handling on the other size raise a clean exception
+(is currently not right)
+
+  $ cat ../genfailed.hg2 | hg unbundle2
+  0 unread bytes
+  abort: stream ended unexpectedly (got 0 bytes, expected 4)
+  [255]
+
+
+  $ cd ..