##// END OF EJS Templates
progress: extract stubs to restart ferr.flush() and .write() on EINTR
progress: extract stubs to restart ferr.flush() and .write() on EINTR

File last commit:

r28800:544908ae default
r32048:c3ef33fd default
Show More
test-batching.py
180 lines | 5.5 KiB | text/x-python | PythonLexer
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 # test-batching.py - tests for transparent command batching
#
# Copyright 2011 Peter Arrenbrecht <peter@arrenbrecht.ch>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Robert Stanca
py3: use print_function in test-batching.py
r28732 from __future__ import absolute_import, print_function
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800
from mercurial import (
peer,
wireproto,
Robert Stanca
py3: use absolute_import in test-batching.py
r28731 )
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# equivalent of repo.repository
class thing(object):
def hello(self):
return "Ready."
# equivalent of localrepo.localrepository
class localthing(thing):
def foo(self, one, two=None):
if one:
return "%s and %s" % (one, two,)
return "Nope"
def bar(self, b, a):
return "%s und %s" % (b, a,)
def greet(self, name=None):
return "Hello, %s" % name
def batch(self):
'''Support for local batching.'''
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 return peer.localbatch(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# usage of "thing" interface
def use(it):
# Direct call to base method shared between client and server.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(it.hello())
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# Direct calls to proxied methods. They cause individual roundtrips.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(it.foo("Un", two="Deux"))
print(it.bar("Eins", "Zwei"))
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# Batched call to a couple of (possibly proxied) methods.
batch = it.batch()
# The calls return futures to eventually hold results.
foo = batch.foo(one="One", two="Two")
foo2 = batch.foo(None)
bar = batch.bar("Eins", "Zwei")
# We can call non-batchable proxy methods, but the break the current batch
# request and cause additional roundtrips.
greet = batch.greet(name="John Smith")
# We can also add local methods into the mix, but they break the batch too.
hello = batch.hello()
bar2 = batch.bar(b="Uno", a="Due")
# Only now are all the calls executed in sequence, with as few roundtrips
# as possible.
batch.submit()
# After the call to submit, the futures actually contain values.
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(foo.value)
print(foo2.value)
print(bar.value)
print(greet.value)
print(hello.value)
print(bar2.value)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
# local usage
mylocal = localthing()
Robert Stanca
py3: use print_function in test-batching.py
r28732 print()
print("== Local")
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 use(mylocal)
# demo remoting; mimicks what wireproto and HTTP/SSH do
# shared
def escapearg(plain):
return (plain
.replace(':', '::')
.replace(',', ':,')
.replace(';', ':;')
.replace('=', ':='))
def unescapearg(escaped):
return (escaped
.replace(':=', '=')
.replace(':;', ';')
.replace(':,', ',')
.replace('::', ':'))
# server side
# equivalent of wireproto's global functions
Thomas Arendsen Hein
classes: fix class style problems found by b071cd58af50...
r14764 class server(object):
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def __init__(self, local):
self.local = local
def _call(self, name, args):
args = dict(arg.split('=', 1) for arg in args)
return getattr(self, name)(**args)
def perform(self, req):
Robert Stanca
py3: use print_function in test-batching.py
r28732 print("REQ:", req)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 name, args = req.split('?', 1)
args = args.split('&')
vals = dict(arg.split('=', 1) for arg in args)
res = getattr(self, name)(**vals)
Robert Stanca
py3: use print_function in test-batching.py
r28732 print(" ->", res)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 return res
def batch(self, cmds):
res = []
for pair in cmds.split(';'):
name, args = pair.split(':', 1)
vals = {}
for a in args.split(','):
if a:
n, v = a.split('=')
vals[n] = unescapearg(v)
res.append(escapearg(getattr(self, name)(**vals)))
return ';'.join(res)
def foo(self, one, two):
return mangle(self.local.foo(unmangle(one), unmangle(two)))
def bar(self, b, a):
return mangle(self.local.bar(unmangle(b), unmangle(a)))
def greet(self, name):
return mangle(self.local.greet(unmangle(name)))
myserver = server(mylocal)
# local side
# equivalent of wireproto.encode/decodelist, that is, type-specific marshalling
# here we just transform the strings a bit to check we're properly en-/decoding
def mangle(s):
return ''.join(chr(ord(c) + 1) for c in s)
def unmangle(s):
return ''.join(chr(ord(c) - 1) for c in s)
# equivalent of wireproto.wirerepository and something like http's wire format
class remotething(thing):
def __init__(self, server):
self.server = server
def _submitone(self, name, args):
req = name + '?' + '&'.join(['%s=%s' % (n, v) for n, v in args])
return self.server.perform(req)
def _submitbatch(self, cmds):
req = []
for name, args in cmds:
args = ','.join(n + '=' + escapearg(v) for n, v in args)
req.append(name + ':' + args)
req = ';'.join(req)
res = self._submitone('batch', [('cmds', req,)])
return res.split(';')
def batch(self):
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 return wireproto.remotebatch(self)
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 @peer.batchable
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def foo(self, one, two=None):
if not one:
yield "Nope", None
encargs = [('one', mangle(one),), ('two', mangle(two),)]
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 encresref = peer.future()
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 yield encargs, encresref
yield unmangle(encresref.value)
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 @peer.batchable
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 def bar(self, b, a):
Yuya Nishihara
test-batching: stop direct symbol import of mercurial modules...
r28800 encresref = peer.future()
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 yield [('b', mangle(b),), ('a', mangle(a),)], encresref
yield unmangle(encresref.value)
# greet is coded directly. It therefore does not support batching. If it
# does appear in a batch, the batch is split around greet, and the call to
# greet is done in its own roundtrip.
def greet(self, name=None):
return unmangle(self._submitone('greet', [('name', mangle(name),)]))
# demo remote usage
myproxy = remotething(myserver)
Robert Stanca
py3: use print_function in test-batching.py
r28732 print()
print("== Remote")
Peter Arrenbrecht
wireproto: add basic command batching infrastructure...
r14621 use(myproxy)