test-wireproto-serverreactor.py
821 lines
| 27.4 KiB
| text/x-python
|
PythonLexer
/ tests / test-wireproto-serverreactor.py
Gregory Szorc
|
r37070 | from __future__ import absolute_import, print_function | ||
import unittest | ||||
from mercurial import ( | ||||
Gregory Szorc
|
r40165 | ui as uimod, | ||
Gregory Szorc
|
r37070 | util, | ||
wireprotoframing as framing, | ||||
) | ||||
Augie Fackler
|
r43346 | from mercurial.utils import cborutil | ||
Gregory Szorc
|
r37070 | |||
ffs = framing.makeframefromhumanstring | ||||
Augie Fackler
|
r41172 | OK = b''.join(cborutil.streamencode({b'status': b'ok'})) | ||
Gregory Szorc
|
r37743 | |||
Augie Fackler
|
r43346 | |||
Gregory Szorc
|
r37074 | def makereactor(deferoutput=False): | ||
Gregory Szorc
|
r40165 | ui = uimod.ui() | ||
return framing.serverreactor(ui, deferoutput=deferoutput) | ||||
Gregory Szorc
|
r37070 | |||
Augie Fackler
|
r43346 | |||
Gregory Szorc
|
r37070 | def sendframes(reactor, gen): | ||
"""Send a generator of frame bytearray to a reactor. | ||||
Emits a generator of results from ``onframerecv()`` calls. | ||||
""" | ||||
for frame in gen: | ||||
Gregory Szorc
|
r37079 | header = framing.parseheader(frame) | ||
Augie Fackler
|
r43346 | payload = frame[framing.FRAME_HEADER_SIZE :] | ||
Gregory Szorc
|
r37079 | assert len(payload) == header.length | ||
Gregory Szorc
|
r37070 | |||
Augie Fackler
|
r43346 | yield reactor.onframerecv( | ||
framing.frame( | ||||
header.requestid, | ||||
header.streamid, | ||||
header.streamflags, | ||||
header.typeid, | ||||
header.flags, | ||||
payload, | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37303 | def sendcommandframes(reactor, stream, rid, cmd, args, datafh=None): | ||
Gregory Szorc
|
r37070 | """Generate frames to run a command and send them to a reactor.""" | ||
Augie Fackler
|
r43346 | return sendframes( | ||
reactor, framing.createcommandframes(stream, rid, cmd, args, datafh) | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37078 | |||
Gregory Szorc
|
r37070 | class ServerReactorTests(unittest.TestCase): | ||
Gregory Szorc
|
r37302 | def _sendsingleframe(self, reactor, f): | ||
results = list(sendframes(reactor, [f])) | ||||
Gregory Szorc
|
r37070 | self.assertEqual(len(results), 1) | ||
return results[0] | ||||
def assertaction(self, res, expected): | ||||
self.assertIsInstance(res, tuple) | ||||
self.assertEqual(len(res), 2) | ||||
self.assertIsInstance(res[1], dict) | ||||
self.assertEqual(res[0], expected) | ||||
Gregory Szorc
|
r37073 | def assertframesequal(self, frames, framestrings): | ||
expected = [ffs(s) for s in framestrings] | ||||
self.assertEqual(list(frames), expected) | ||||
Gregory Szorc
|
r37070 | def test1framecommand(self): | ||
"""Receiving a command in a single frame yields request to run it.""" | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | stream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | results = list(sendcommandframes(reactor, stream, 1, b'mycommand', {})) | ||
Gregory Szorc
|
r37070 | self.assertEqual(len(results), 1) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'runcommand') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[0][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'mycommand', | ||||
b'args': {}, | ||||
b'redirect': None, | ||||
b'data': None, | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37074 | result = reactor.oninputeof() | ||
Augie Fackler
|
r37700 | self.assertaction(result, b'noop') | ||
Gregory Szorc
|
r37074 | |||
Gregory Szorc
|
r37070 | def test1argument(self): | ||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | stream = framing.stream(1) | ||
Augie Fackler
|
r43346 | results = list( | ||
sendcommandframes( | ||||
reactor, stream, 41, b'mycommand', {b'foo': b'bar'} | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37308 | self.assertEqual(len(results), 1) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'runcommand') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[0][1], | ||||
{ | ||||
b'requestid': 41, | ||||
b'command': b'mycommand', | ||||
b'args': {b'foo': b'bar'}, | ||||
b'redirect': None, | ||||
b'data': None, | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
def testmultiarguments(self): | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | stream = framing.stream(1) | ||
Augie Fackler
|
r43346 | results = list( | ||
sendcommandframes( | ||||
reactor, | ||||
stream, | ||||
1, | ||||
b'mycommand', | ||||
{b'foo': b'bar', b'biz': b'baz'}, | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37308 | self.assertEqual(len(results), 1) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'runcommand') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[0][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'mycommand', | ||||
b'args': {b'foo': b'bar', b'biz': b'baz'}, | ||||
b'redirect': None, | ||||
b'data': None, | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
def testsimplecommanddata(self): | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | stream = framing.stream(1) | ||
Augie Fackler
|
r43346 | results = list( | ||
sendcommandframes( | ||||
reactor, stream, 1, b'mycommand', {}, util.bytesio(b'data!') | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37070 | self.assertEqual(len(results), 2) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'wantframe') | ||
self.assertaction(results[1], b'runcommand') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[1][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'mycommand', | ||||
b'args': {}, | ||||
b'redirect': None, | ||||
b'data': b'data!', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
def testmultipledataframes(self): | ||||
frames = [ | ||||
Augie Fackler
|
r43346 | ffs( | ||
b'1 1 stream-begin command-request new|have-data ' | ||||
b"cbor:{b'name': b'mycommand'}" | ||||
), | ||||
Gregory Szorc
|
r37304 | ffs(b'1 1 0 command-data continuation data1'), | ||
ffs(b'1 1 0 command-data continuation data2'), | ||||
ffs(b'1 1 0 command-data eos data3'), | ||||
Gregory Szorc
|
r37070 | ] | ||
reactor = makereactor() | ||||
results = list(sendframes(reactor, frames)) | ||||
self.assertEqual(len(results), 4) | ||||
for i in range(3): | ||||
Augie Fackler
|
r37700 | self.assertaction(results[i], b'wantframe') | ||
self.assertaction(results[3], b'runcommand') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[3][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'mycommand', | ||||
b'args': {}, | ||||
b'redirect': None, | ||||
b'data': b'data1data2data3', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
def testargumentanddata(self): | ||||
frames = [ | ||||
Augie Fackler
|
r43346 | ffs( | ||
b'1 1 stream-begin command-request new|have-data ' | ||||
Gregory Szorc
|
r37308 | b"cbor:{b'name': b'command', b'args': {b'key': b'val'," | ||
Augie Fackler
|
r43346 | b"b'foo': b'bar'}}" | ||
), | ||||
Gregory Szorc
|
r37304 | ffs(b'1 1 0 command-data continuation value1'), | ||
ffs(b'1 1 0 command-data eos value2'), | ||||
Gregory Szorc
|
r37070 | ] | ||
reactor = makereactor() | ||||
results = list(sendframes(reactor, frames)) | ||||
Augie Fackler
|
r37700 | self.assertaction(results[-1], b'runcommand') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[-1][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'command', | ||||
b'args': {b'key': b'val', b'foo': b'bar',}, | ||||
b'redirect': None, | ||||
b'data': b'value1value2', | ||||
Gregory Szorc
|
r37070 | }, | ||
Augie Fackler
|
r43346 | ) | ||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37308 | def testnewandcontinuation(self): | ||
Augie Fackler
|
r43346 | result = self._sendsingleframe( | ||
makereactor(), | ||||
ffs(b'1 1 stream-begin command-request new|continuation '), | ||||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'received command request frame with both new and ' | ||||
b'continuation flags set', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37308 | def testneithernewnorcontinuation(self): | ||
Augie Fackler
|
r43346 | result = self._sendsingleframe( | ||
makereactor(), ffs(b'1 1 stream-begin command-request 0 ') | ||||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'received command request frame with neither new nor ' | ||||
b'continuation flags set', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Gregory Szorc
|
r37070 | def testunexpectedcommanddata(self): | ||
Gregory Szorc
|
r37308 | """Command data frame when not running a command is an error.""" | ||
Augie Fackler
|
r43346 | result = self._sendsingleframe( | ||
makereactor(), ffs(b'1 1 stream-begin command-data 0 ignored') | ||||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'expected sender protocol settings or command request ' | ||||
b'frame; got 2', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37076 | def testunexpectedcommanddatareceiving(self): | ||
"""Same as above except the command is receiving.""" | ||||
Augie Fackler
|
r43346 | results = list( | ||
sendframes( | ||||
makereactor(), | ||||
[ | ||||
ffs( | ||||
b'1 1 stream-begin command-request new|more ' | ||||
b"cbor:{b'name': b'ignored'}" | ||||
), | ||||
ffs(b'1 1 0 command-data eos ignored'), | ||||
], | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'wantframe') | ||
self.assertaction(results[1], b'error') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[1][1], | ||||
{ | ||||
b'message': b'received command data frame for request that is not ' | ||||
b'expecting data: 1', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Gregory Szorc
|
r37302 | def testconflictingrequestidallowed(self): | ||
Gregory Szorc
|
r37076 | """Multiple fully serviced commands with same request ID is allowed.""" | ||
Gregory Szorc
|
r37302 | reactor = makereactor() | ||
results = [] | ||||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Augie Fackler
|
r43346 | results.append( | ||
self._sendsingleframe( | ||||
reactor, | ||||
ffs( | ||||
b'1 1 stream-begin command-request new ' | ||||
b"cbor:{b'name': b'command'}" | ||||
), | ||||
) | ||||
) | ||||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [b'response1'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
list(result[1][b'framegen']) | ||||
Augie Fackler
|
r43346 | results.append( | ||
self._sendsingleframe( | ||||
reactor, | ||||
ffs( | ||||
b'1 1 stream-begin command-request new ' | ||||
b"cbor:{b'name': b'command'}" | ||||
), | ||||
) | ||||
) | ||||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [b'response2'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
list(result[1][b'framegen']) | ||||
Augie Fackler
|
r43346 | results.append( | ||
self._sendsingleframe( | ||||
reactor, | ||||
ffs( | ||||
b'1 1 stream-begin command-request new ' | ||||
b"cbor:{b'name': b'command'}" | ||||
), | ||||
) | ||||
) | ||||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [b'response3'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
list(result[1][b'framegen']) | ||||
Gregory Szorc
|
r37302 | |||
Gregory Szorc
|
r37076 | for i in range(3): | ||
Augie Fackler
|
r37700 | self.assertaction(results[i], b'runcommand') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[i][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'command', | ||||
b'args': {}, | ||||
b'redirect': None, | ||||
b'data': None, | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
def testconflictingrequestid(self): | ||||
"""Request ID for new command matching in-flight command is illegal.""" | ||||
Augie Fackler
|
r43346 | results = list( | ||
sendframes( | ||||
makereactor(), | ||||
[ | ||||
ffs( | ||||
b'1 1 stream-begin command-request new|more ' | ||||
b"cbor:{b'name': b'command'}" | ||||
), | ||||
ffs( | ||||
b'1 1 0 command-request new ' | ||||
b"cbor:{b'name': b'command1'}" | ||||
), | ||||
], | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'wantframe') | ||
self.assertaction(results[1], b'error') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[1][1], {b'message': b'request with ID 1 already received',} | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
def testinterleavedcommands(self): | ||||
Augie Fackler
|
r43346 | cbor1 = b''.join( | ||
cborutil.streamencode( | ||||
{ | ||||
b'name': b'command1', | ||||
b'args': {b'foo': b'bar', b'key1': b'val',}, | ||||
} | ||||
) | ||||
) | ||||
cbor3 = b''.join( | ||||
cborutil.streamencode( | ||||
{ | ||||
b'name': b'command3', | ||||
b'args': {b'biz': b'baz', b'key': b'val',}, | ||||
} | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Augie Fackler
|
r43346 | results = list( | ||
sendframes( | ||||
makereactor(), | ||||
[ | ||||
ffs( | ||||
b'1 1 stream-begin command-request new|more %s' | ||||
% cbor1[0:6] | ||||
), | ||||
ffs(b'3 1 0 command-request new|more %s' % cbor3[0:10]), | ||||
ffs( | ||||
b'1 1 0 command-request continuation|more %s' | ||||
% cbor1[6:9] | ||||
), | ||||
ffs( | ||||
b'3 1 0 command-request continuation|more %s' | ||||
% cbor3[10:13] | ||||
), | ||||
ffs(b'3 1 0 command-request continuation %s' % cbor3[13:]), | ||||
ffs(b'1 1 0 command-request continuation %s' % cbor1[9:]), | ||||
], | ||||
) | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Augie Fackler
|
r43346 | self.assertEqual( | ||
[t[0] for t in results], | ||||
[ | ||||
b'wantframe', | ||||
b'wantframe', | ||||
b'wantframe', | ||||
b'wantframe', | ||||
b'runcommand', | ||||
b'runcommand', | ||||
], | ||||
) | ||||
self.assertEqual( | ||||
results[4][1], | ||||
{ | ||||
b'requestid': 3, | ||||
b'command': b'command3', | ||||
b'args': {b'biz': b'baz', b'key': b'val'}, | ||||
b'redirect': None, | ||||
b'data': None, | ||||
}, | ||||
) | ||||
self.assertEqual( | ||||
results[5][1], | ||||
{ | ||||
b'requestid': 1, | ||||
b'command': b'command1', | ||||
b'args': {b'foo': b'bar', b'key1': b'val'}, | ||||
b'redirect': None, | ||||
b'data': None, | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Gregory Szorc
|
r37070 | def testmissingcommanddataframe(self): | ||
Gregory Szorc
|
r37076 | # The reactor doesn't currently handle partially received commands. | ||
# So this test is failing to do anything with request 1. | ||||
Gregory Szorc
|
r37070 | frames = [ | ||
Augie Fackler
|
r43346 | ffs( | ||
b'1 1 stream-begin command-request new|have-data ' | ||||
b"cbor:{b'name': b'command1'}" | ||||
), | ||||
ffs(b'3 1 0 command-request new ' b"cbor:{b'name': b'command2'}"), | ||||
Gregory Szorc
|
r37070 | ] | ||
results = list(sendframes(makereactor(), frames)) | ||||
self.assertEqual(len(results), 2) | ||||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'wantframe') | ||
self.assertaction(results[1], b'runcommand') | ||||
Gregory Szorc
|
r37070 | |||
def testmissingcommanddataframeflags(self): | ||||
frames = [ | ||||
Augie Fackler
|
r43346 | ffs( | ||
b'1 1 stream-begin command-request new|have-data ' | ||||
b"cbor:{b'name': b'command1'}" | ||||
), | ||||
Gregory Szorc
|
r37304 | ffs(b'1 1 0 command-data 0 data'), | ||
Gregory Szorc
|
r37070 | ] | ||
results = list(sendframes(makereactor(), frames)) | ||||
self.assertEqual(len(results), 2) | ||||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'wantframe') | ||
self.assertaction(results[1], b'error') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[1][1], {b'message': b'command data frame without flags',} | ||||
) | ||||
Gregory Szorc
|
r37070 | |||
Gregory Szorc
|
r37076 | def testframefornonreceivingrequest(self): | ||
"""Receiving a frame for a command that is not receiving is illegal.""" | ||||
Augie Fackler
|
r43346 | results = list( | ||
sendframes( | ||||
makereactor(), | ||||
[ | ||||
ffs( | ||||
b'1 1 stream-begin command-request new ' | ||||
b"cbor:{b'name': b'command1'}" | ||||
), | ||||
ffs( | ||||
b'3 1 0 command-request new|have-data ' | ||||
b"cbor:{b'name': b'command3'}" | ||||
), | ||||
ffs(b'5 1 0 command-data eos ignored'), | ||||
], | ||||
) | ||||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(results[2], b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[2][1], | ||||
{ | ||||
b'message': b'received frame for request that is not receiving: 5', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r37076 | |||
Gregory Szorc
|
r37073 | def testsimpleresponse(self): | ||
"""Bytes response to command sends result frames.""" | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) | ||
Gregory Szorc
|
r37073 | |||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [b'response'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
Augie Fackler
|
r43346 | self.assertframesequal( | ||
result[1][b'framegen'], | ||||
[ | ||||
b'1 2 stream-begin stream-settings eos cbor:b"identity"', | ||||
b'1 2 encoded command-response continuation %s' % OK, | ||||
b'1 2 encoded command-response continuation cbor:b"response"', | ||||
b'1 2 0 command-response eos ', | ||||
], | ||||
) | ||||
Gregory Szorc
|
r37073 | |||
def testmultiframeresponse(self): | ||||
"""Bytes response spanning multiple frames is handled.""" | ||||
first = b'x' * framing.DEFAULT_MAX_FRAME_SIZE | ||||
second = b'y' * 100 | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) | ||
Gregory Szorc
|
r37073 | |||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [first + second] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
Augie Fackler
|
r43346 | self.assertframesequal( | ||
result[1][b'framegen'], | ||||
[ | ||||
b'1 2 stream-begin stream-settings eos cbor:b"identity"', | ||||
b'1 2 encoded command-response continuation %s' % OK, | ||||
b'1 2 encoded command-response continuation Y\x80d', | ||||
b'1 2 encoded command-response continuation %s' % first, | ||||
b'1 2 encoded command-response continuation %s' % second, | ||||
b'1 2 0 command-response eos ', | ||||
], | ||||
) | ||||
Gregory Szorc
|
r37073 | |||
Gregory Szorc
|
r37744 | def testservererror(self): | ||
Gregory Szorc
|
r37073 | reactor = makereactor() | ||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'mycommand', {})) | ||
Gregory Szorc
|
r37073 | |||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r37744 | result = reactor.onservererror(outstream, 1, b'some message') | ||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
Augie Fackler
|
r43346 | self.assertframesequal( | ||
result[1][b'framegen'], | ||||
[ | ||||
b"1 2 stream-begin error-response 0 " | ||||
b"cbor:{b'type': b'server', " | ||||
b"b'message': [{b'msg': b'some message'}]}", | ||||
], | ||||
) | ||||
Gregory Szorc
|
r37073 | |||
Gregory Szorc
|
r37074 | def test1commanddeferresponse(self): | ||
"""Responses when in deferred output mode are delayed until EOF.""" | ||||
reactor = makereactor(deferoutput=True) | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Augie Fackler
|
r43346 | results = list( | ||
sendcommandframes(reactor, instream, 1, b'mycommand', {}) | ||||
) | ||||
Gregory Szorc
|
r37074 | self.assertEqual(len(results), 1) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'runcommand') | ||
Gregory Szorc
|
r37074 | |||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [b'response'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'noop') | ||
Gregory Szorc
|
r37074 | result = reactor.oninputeof() | ||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
Augie Fackler
|
r43346 | self.assertframesequal( | ||
result[1][b'framegen'], | ||||
[ | ||||
b'1 2 stream-begin stream-settings eos cbor:b"identity"', | ||||
b'1 2 encoded command-response continuation %s' % OK, | ||||
b'1 2 encoded command-response continuation cbor:b"response"', | ||||
b'1 2 0 command-response eos ', | ||||
], | ||||
) | ||||
Gregory Szorc
|
r37074 | |||
def testmultiplecommanddeferresponse(self): | ||||
reactor = makereactor(deferoutput=True) | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'command1', {})) | ||
list(sendcommandframes(reactor, instream, 3, b'command2', {})) | ||||
Gregory Szorc
|
r37074 | |||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 1, [b'response1'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'noop') | ||
Gregory Szorc
|
r40170 | result = reactor.oncommandresponsereadyobjects( | ||
Augie Fackler
|
r43346 | outstream, 3, [b'response2'] | ||
) | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'noop') | ||
Gregory Szorc
|
r37074 | result = reactor.oninputeof() | ||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
Augie Fackler
|
r43346 | self.assertframesequal( | ||
result[1][b'framegen'], | ||||
[ | ||||
b'1 2 stream-begin stream-settings eos cbor:b"identity"', | ||||
b'1 2 encoded command-response continuation %s' % OK, | ||||
b'1 2 encoded command-response continuation cbor:b"response1"', | ||||
b'1 2 0 command-response eos ', | ||||
b'3 2 encoded command-response continuation %s' % OK, | ||||
b'3 2 encoded command-response continuation cbor:b"response2"', | ||||
b'3 2 0 command-response eos ', | ||||
], | ||||
) | ||||
Gregory Szorc
|
r37075 | |||
def testrequestidtracking(self): | ||||
reactor = makereactor(deferoutput=True) | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'command1', {})) | ||
list(sendcommandframes(reactor, instream, 3, b'command2', {})) | ||||
list(sendcommandframes(reactor, instream, 5, b'command3', {})) | ||||
Gregory Szorc
|
r37075 | |||
# Register results for commands out of order. | ||||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | reactor.oncommandresponsereadyobjects(outstream, 3, [b'response3']) | ||
reactor.oncommandresponsereadyobjects(outstream, 1, [b'response1']) | ||||
reactor.oncommandresponsereadyobjects(outstream, 5, [b'response5']) | ||||
Gregory Szorc
|
r37075 | |||
result = reactor.oninputeof() | ||||
Augie Fackler
|
r37700 | self.assertaction(result, b'sendframes') | ||
Augie Fackler
|
r43346 | self.assertframesequal( | ||
result[1][b'framegen'], | ||||
[ | ||||
b'3 2 stream-begin stream-settings eos cbor:b"identity"', | ||||
b'3 2 encoded command-response continuation %s' % OK, | ||||
b'3 2 encoded command-response continuation cbor:b"response3"', | ||||
b'3 2 0 command-response eos ', | ||||
b'1 2 encoded command-response continuation %s' % OK, | ||||
b'1 2 encoded command-response continuation cbor:b"response1"', | ||||
b'1 2 0 command-response eos ', | ||||
b'5 2 encoded command-response continuation %s' % OK, | ||||
b'5 2 encoded command-response continuation cbor:b"response5"', | ||||
b'5 2 0 command-response eos ', | ||||
], | ||||
) | ||||
Gregory Szorc
|
r37074 | |||
Gregory Szorc
|
r37081 | def testduplicaterequestonactivecommand(self): | ||
"""Receiving a request ID that matches a request that isn't finished.""" | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | stream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, stream, 1, b'command1', {})) | ||
results = list(sendcommandframes(reactor, stream, 1, b'command1', {})) | ||||
Gregory Szorc
|
r37081 | |||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[0][1], {b'message': b'request with ID 1 is already active',} | ||||
) | ||||
Gregory Szorc
|
r37081 | |||
def testduplicaterequestonactivecommandnosend(self): | ||||
"""Same as above but we've registered a response but haven't sent it.""" | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'command1', {})) | ||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | reactor.oncommandresponsereadyobjects(outstream, 1, [b'response']) | ||
Gregory Szorc
|
r37081 | |||
# We've registered the response but haven't sent it. From the | ||||
# perspective of the reactor, the command is still active. | ||||
Gregory Szorc
|
r37303 | results = list(sendcommandframes(reactor, instream, 1, b'command1', {})) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
results[0][1], {b'message': b'request with ID 1 is already active',} | ||||
) | ||||
Gregory Szorc
|
r37081 | |||
def testduplicaterequestaftersend(self): | ||||
"""We can use a duplicate request ID after we've sent the response.""" | ||||
reactor = makereactor() | ||||
Gregory Szorc
|
r37304 | instream = framing.stream(1) | ||
Gregory Szorc
|
r37303 | list(sendcommandframes(reactor, instream, 1, b'command1', {})) | ||
Gregory Szorc
|
r37305 | outstream = reactor.makeoutputstream() | ||
Gregory Szorc
|
r40170 | res = reactor.oncommandresponsereadyobjects(outstream, 1, [b'response']) | ||
Augie Fackler
|
r37700 | list(res[1][b'framegen']) | ||
Gregory Szorc
|
r37081 | |||
Gregory Szorc
|
r37303 | results = list(sendcommandframes(reactor, instream, 1, b'command1', {})) | ||
Augie Fackler
|
r37700 | self.assertaction(results[0], b'runcommand') | ||
Gregory Szorc
|
r37081 | |||
Gregory Szorc
|
r40162 | def testprotocolsettingsnoflags(self): | ||
result = self._sendsingleframe( | ||||
Augie Fackler
|
r43346 | makereactor(), ffs(b'0 1 stream-begin sender-protocol-settings 0 ') | ||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'sender protocol settings frame must have ' | ||||
b'continuation or end of stream flag set', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
def testprotocolsettingsconflictflags(self): | ||||
result = self._sendsingleframe( | ||||
makereactor(), | ||||
Augie Fackler
|
r43346 | ffs(b'0 1 stream-begin sender-protocol-settings continuation|eos '), | ||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'sender protocol settings frame cannot have both ' | ||||
b'continuation and end of stream flags set', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
def testprotocolsettingsemptypayload(self): | ||||
result = self._sendsingleframe( | ||||
makereactor(), | ||||
Augie Fackler
|
r43346 | ffs(b'0 1 stream-begin sender-protocol-settings eos '), | ||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'sender protocol settings frame did not contain CBOR ' | ||||
b'data', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
def testprotocolsettingsmultipleobjects(self): | ||||
result = self._sendsingleframe( | ||||
makereactor(), | ||||
Augie Fackler
|
r43346 | ffs( | ||
b'0 1 stream-begin sender-protocol-settings eos ' | ||||
b'\x46foobar\x43foo' | ||||
), | ||||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], | ||||
{ | ||||
b'message': b'sender protocol settings frame contained multiple ' | ||||
b'CBOR values', | ||||
}, | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
def testprotocolsettingscontentencodings(self): | ||||
reactor = makereactor() | ||||
result = self._sendsingleframe( | ||||
reactor, | ||||
Augie Fackler
|
r43346 | ffs( | ||
b'0 1 stream-begin sender-protocol-settings eos ' | ||||
b'cbor:{b"contentencodings": [b"a", b"b"]}' | ||||
), | ||||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'wantframe') | ||
self.assertEqual(reactor._state, b'idle') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
reactor._sendersettings[b'contentencodings'], [b'a', b'b'] | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
def testprotocolsettingsmultipleframes(self): | ||||
reactor = makereactor() | ||||
Augie Fackler
|
r43346 | data = b''.join( | ||
cborutil.streamencode( | ||||
{b'contentencodings': [b'value1', b'value2'],} | ||||
) | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
Augie Fackler
|
r43346 | results = list( | ||
sendframes( | ||||
reactor, | ||||
[ | ||||
ffs( | ||||
b'0 1 stream-begin sender-protocol-settings continuation %s' | ||||
% data[0:5] | ||||
), | ||||
ffs(b'0 1 0 sender-protocol-settings eos %s' % data[5:]), | ||||
], | ||||
) | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
self.assertEqual(len(results), 2) | ||||
self.assertaction(results[0], b'wantframe') | ||||
self.assertaction(results[1], b'wantframe') | ||||
self.assertEqual(reactor._state, b'idle') | ||||
Augie Fackler
|
r43346 | self.assertEqual( | ||
reactor._sendersettings[b'contentencodings'], [b'value1', b'value2'] | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
def testprotocolsettingsbadcbor(self): | ||||
result = self._sendsingleframe( | ||||
makereactor(), | ||||
Augie Fackler
|
r43346 | ffs(b'0 1 stream-begin sender-protocol-settings eos badvalue'), | ||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'error') | ||
def testprotocolsettingsnoninitial(self): | ||||
# Cannot have protocol settings frames as non-initial frames. | ||||
reactor = makereactor() | ||||
stream = framing.stream(1) | ||||
results = list(sendcommandframes(reactor, stream, 1, b'mycommand', {})) | ||||
self.assertEqual(len(results), 1) | ||||
self.assertaction(results[0], b'runcommand') | ||||
result = self._sendsingleframe( | ||||
Augie Fackler
|
r43346 | reactor, ffs(b'0 1 0 sender-protocol-settings eos ') | ||
) | ||||
Gregory Szorc
|
r40162 | self.assertaction(result, b'error') | ||
Augie Fackler
|
r43346 | self.assertEqual( | ||
result[1], {b'message': b'expected command request frame; got 8',} | ||||
) | ||||
Gregory Szorc
|
r40162 | |||
Gregory Szorc
|
r37070 | if __name__ == '__main__': | ||
import silenttestrunner | ||||
Augie Fackler
|
r43346 | |||
Gregory Szorc
|
r37070 | silenttestrunner.main(__name__) | ||