def test_failAll(self): sent = ListLog() def sendQANFrame(frame): sent.append(frame) h = QANHelper(None, None, sendQANFrame, None) d1 = h.ask("going to the theater?") d2 = h.ask("mu?") self.assertEqual([ Question("going to the theater?", 1), Question("mu?", 2), ], sent.getNew()) h.failAll("just because") self.assertTrue(d1.called) d1_ = self.assertFailure(d1, QuestionFailed) d1_.addCallback(lambda e: self.assertEqual("just because", str(e))) assert d1_.called self.assertTrue(d2.called) d2_ = self.assertFailure(d2, QuestionFailed) d2_.addCallback(lambda e: self.assertEqual("just because", str(e))) assert d2_.called # Peer can still send an answer to the failed Questions h.handleQANFrame(OkayAnswer("no", 1)) h.handleQANFrame(KnownErrorAnswer("what?", 2))
def __init__(self, request=None): self.log = ListLog() self.pretendGotHello() if request: self.writable = request self._isHttp = True else: self._isHttp = False
def test_questionReceivedDuplicateQid(self): received = ListLog() def bodyReceived(body, isQuestion): received.append((body, isQuestion)) return defer.Deferred() nonlocal = dict(fatalReason=None) def fatalError(reason): nonlocal['fatalReason'] = reason h = QANHelper(bodyReceived, None, None, fatalError) h.handleQANFrame(Question("what?", 1)) h.handleQANFrame(Question("where?", 1)) self.assertEqual([("what?", True)], received.getNew()) self.assertEqual("Received Question with duplicate qid: 1", nonlocal['fatalReason'])
class FrameDecodingTcpTransport(DummyTCPTransport): """ A TCP transport that first decodes bytes with a parser, then decodes the Minerva frames with decodeFrameFromServer. """ def __init__(self, parser): self.parser = parser self.log = ListLog() def getNew(self): return self.log.getNew() def write(self, data): frames, code = strictGetNewFrames(self.parser, data) self.log.extend(decodeFrameFromServer( StringFragment(f, 0, len(f)) if isinstance(f, str) else f) for f in frames)
def streamStarted(self, stream): self.factory.instances.add(self) self.log = ListLog() self.log.append(['streamStarted', stream]) self.stream = stream if 'streamStarted' in self._callFrom: self._callStuff() if 'streamStarted' in self._raiseFrom: raise self._raiseWhat()
class _MockStringProtocol(object): implements(IStringProtocol) def __init__(self, callFrom=(), callWhat=(), raiseFrom=(), raiseWhat=None): assert isinstance(callFrom, tuple), callFrom assert isinstance(callWhat, tuple), callWhat assert isinstance(raiseFrom, tuple), raiseFrom self._callFrom = callFrom self._callWhat = callWhat self._raiseFrom = raiseFrom self._raiseWhat = raiseWhat def _callStuff(self): if 'sendString' in self._callWhat: self.stream.sendString("s2cstring0") self.stream.sendString("s2cstring1") self.stream.sendString("s2cstring2") if 'reset' in self._callWhat: self.stream.reset('reset forced by mock protocol') def streamStarted(self, stream): self.factory.instances.add(self) self.log = ListLog() self.log.append(['streamStarted', stream]) self.stream = stream if 'streamStarted' in self._callFrom: self._callStuff() if 'streamStarted' in self._raiseFrom: raise self._raiseWhat() def getNew(self): return self.log.getNew() def streamReset(self, reasonString, applicationLevel): self.log.append(['streamReset', reasonString, applicationLevel]) if 'streamReset' in self._raiseFrom: raise self._raiseWhat()
def __init__(self, clock=None, streamId=None, streamProtocolFactory=None): ## if streamId is None: # make a random one? self._notifications = [] self.streamId = streamId self.streamProtocolFactory = streamProtocolFactory self.log = ListLog() self._incoming = Incoming() self.queue = Queue() self._transports = set() self.allSeenTransports = [] self.lastSackSeenByServer = SACK(-1, ())
def test_notificationCausesException(self): """ A Notification that causes bodyReceived to raise an exception leads to a call to logError, and no response sent to the peer. """ loggedErrors = [] def logError(message, failure): loggedErrors.append((message, failure)) def bodyReceived(body, isQuestion): raise ValueError("bodyReceived did something wrong") sent = ListLog() def sendQANFrame(frame): sent.append(frame) h = QANHelper(bodyReceived, logError, sendQANFrame, None) h.handleQANFrame(Notification("You've got more mail")) self.assertEqual("Peer's Notification caused uncaught exception", loggedErrors[0][0]) self.assertIsInstance(loggedErrors[0][1], failure.Failure) self.assertEqual([], sent.getNew())
def test_weCancel(self): sent = ListLog() def sendQANFrame(frame): sent.append(frame) h = QANHelper(None, None, sendQANFrame, None) d = h.ask("going to the theater?") self.assertEqual([ Question("going to the theater?", 1), ], sent.getNew()) d.cancel() self.assertEqual([ Cancellation(1), ], sent.getNew()) self.assertTrue(d.called) d2 = self.assertFailure(d, defer.CancelledError) assert d2.called # Peer always sends an answer, which QANHelper must ignore. h.handleQANFrame(OkayAnswer("nope", 1))
def test_questionCausesException(self): """ A Question that causes bodyReceived to raise an exception leads to a call to logError, and an UnknownErrorResponse("Uncaught exception") sent to the peer. """ loggedErrors = [] def logError(message, failure): loggedErrors.append((message, failure)) def bodyReceived(body, isQuestion): raise ValueError("bodyReceived did something wrong") sent = ListLog() def sendQANFrame(frame): sent.append(frame) h = QANHelper(bodyReceived, logError, sendQANFrame, None) h.handleQANFrame(Question("How much wood would a wood chuck chuck?", 1)) self.assertEqual("Peer's Question #1 caused uncaught exception", loggedErrors[0][0]) self.assertIsInstance(loggedErrors[0][1], failure.Failure) self.assertEqual([UnknownErrorAnswer("Uncaught exception", 1)], sent.getNew())
class MockServerStream(object): streamId = "a stream id of unusual length" def __init__(self, clock=None, streamId=None, streamProtocolFactory=None): ## if streamId is None: # make a random one? self._notifications = [] self.streamId = streamId self.streamProtocolFactory = streamProtocolFactory self.log = ListLog() self._incoming = Incoming() self.queue = Queue() self._transports = set() self.allSeenTransports = [] self.lastSackSeenByServer = SACK(-1, ()) def getNew(self): return self.log.getNew() def sendString(self, string): self.log.append(['sendString', string]) def reset(self, reasonString): self.log.append(['reset', reasonString]) def resetFromPeer(self, reasonString, applicationLevel): self.log.append(['resetFromPeer', reasonString, applicationLevel]) for t in self._transports.copy(): t.closeGently() def stringsReceived(self, transport, strings): self.log.append(['stringsReceived', transport, strings]) self._incoming.give(strings) def sackReceived(self, sack): """ Returns C{True} if SACK was bad, C{False} otherwise. """ self.log.append(['sackReceived', sack]) self.lastSackSeenByServer = sack return self.queue.handleSACK(sack) def transportOnline(self, transport, wantsStrings, succeedsTransport): self.allSeenTransports.append(transport) self.log.append(['transportOnline', transport, wantsStrings, succeedsTransport]) assert transport not in self._transports self._transports.add(transport) def transportOffline(self, transport): self.log.append(['transportOffline', transport]) self._transports.remove(transport) def serverShuttingDown(self, transport): self.log.append(['serverShuttingDown', transport]) def pauseProducing(self): self.log.append(['pauseProducing']) def resumeProducing(self): self.log.append(['resumeProducing']) def stopProducing(self): self.log.append(['stopProducing']) def getSACK(self): self.log.append(['getSACK']) return self._incoming.getSACK() def notifyFinish(self): """ Notify when finishing the request @return: A deferred. The deferred will be triggered when the stream is finished -- always with a C{None} value. """ self.log.append(['notifyFinish']) self._notifications.append(defer.Deferred()) return self._notifications[-1] def _pretendFinish(self): for d in self._notifications: d.callback(None) self._notifications = None
def __init__(self, parser): self.parser = parser self.log = ListLog()
class DummySocketLikeTransport(object): request = None globalCounter = [-1] ourSeqNum = -1 _paused = False def __init__(self, request=None): self.log = ListLog() self.pretendGotHello() if request: self.writable = request self._isHttp = True else: self._isHttp = False def getNew(self): return self.log.getNew() def isHttp(self): return self._isHttp def pretendGotHello(self): self.globalCounter[0] += 1 self.transportNumber = self.globalCounter[0] def closeGently(self): self.log.append(['closeGently']) def causedRwinOverflow(self): self.log.append(['causedRwinOverflow']) def writeReset(self, reasonString, applicationLevel): self.log.append(['writeReset', reasonString, applicationLevel]) def writeStrings(self, queue, start): self.log.append(['writeStrings', queue, start]) lastString = self.ourSeqNum for seqNum, string in queue.iterItems(start=start): if lastString == -1 or lastString + 1 != seqNum: pass ##toSend += self._encodeFrame(SeqNumFrame(seqNum)) ##toSend += self._encodeFrame(StringFrame(string)) lastString = seqNum self.ourSeqNum = lastString def registerProducer(self, producer, streaming): self.log.append(['registerProducer', producer, streaming]) def unregisterProducer(self): self.log.append(['unregisterProducer']) def pauseProducing(self): self._paused = True def getHost(self): return None # TODO: return a real host def isStreamingFromPeer(self): return True def isStreamingToPeer(self): return True
def test_ask(self): sent = ListLog() def sendQANFrame(frame): sent.append(frame) answers = ListLog() def gotOkayAnswer(answer): answers.append((answer, 'okay')) def gotErrorAnswerExpect(expectedFailure): def gotErrorAnswer(failure): failure.trap(expectedFailure) answers.append((failure.value[0], 'error')) return gotErrorAnswer fatalErrors = ListLog() def fatalError(msg): fatalErrors.append(msg) h = QANHelper(None, None, sendQANFrame, fatalError) d1 = h.ask("what?") d1.addCallbacks(gotOkayAnswer, gotErrorAnswerExpect(None)) # Make sure QANHelper wrote something to the peer self.assertEqual([ Question("what?", 1), ], sent.getNew()) # We shouldn't have an answer yet self.assertEqual([], answers.getNew()) # An answer with a wrong QID calls fatalError self.assertEqual([], fatalErrors.getNew()) h.handleQANFrame(OkayAnswer("answer with wrong qid", 100)) self.assertEqual(["Received an answer with invalid qid: 100"], fatalErrors.getNew()) ### TODO: we might have to set up a new QANHelper after the fatalError; ### the current implementation is lenient. # Feed this "OkayAnswer from the peer" into QANHelper h.handleQANFrame(OkayAnswer("no.", 1)) self.assertEqual([('no.', 'okay')], answers.getNew()) d2 = h.ask("I want a KnownError response to this one") d2.addCallbacks(gotOkayAnswer, gotErrorAnswerExpect(KnownError)) # Feed this "KnownErrorAnswer from the peer" into QANHelper h.handleQANFrame(KnownErrorAnswer("KnownErrorAnswer as asked", 2)) self.assertEqual([('KnownErrorAnswer as asked', 'error')], answers.getNew()) d3 = h.ask("I want an UnknownError response to this one") d3.addCallbacks(gotOkayAnswer, gotErrorAnswerExpect(UnknownError)) # Feed this "UnknownErrorAnswer from the peer" into QANHelper h.handleQANFrame(UnknownErrorAnswer("UnknownErrorAnswer as asked", 3)) self.assertEqual([('UnknownErrorAnswer as asked', 'error')], answers.getNew())
def test_theyCancel(self): nonlocal = dict( cancellerDoesErrbackCalled=False, cancellerDoesCallbackCalled=False, ) def cancellerDoesErrback(d): nonlocal['cancellerDoesErrbackCalled'] = True d.errback(KnownError("okay, you'll never know")) def cancellerDoesCallback(d): nonlocal['cancellerDoesCallbackCalled'] = True d.callback("maybe a little warm") received = [] answerDs = [ defer.Deferred(), defer.Deferred(cancellerDoesErrback), defer.Deferred(), defer.Deferred(cancellerDoesCallback), ] def bodyReceived(body, isQuestion): received.append((body, isQuestion)) return answerDs.pop(0) sent = ListLog() def sendQANFrame(frame): sent.append(frame) h = QANHelper(bodyReceived, None, sendQANFrame, None) d1 = answerDs[0] d2 = answerDs[1] d3 = answerDs[2] d4 = answerDs[3] h.handleQANFrame(Question("the weather?", 1)) h.handleQANFrame(Question("how about now?", 2)) h.handleQANFrame(Question("and now?", 3)) h.handleQANFrame(Question("this evening?", 4)) self.assertEqual([ ('the weather?', True), ('how about now?', True), ('and now?', True), ('this evening?', True), ], received) self.assertEqual([], sent.getNew()) self.assertEqual(False, nonlocal['cancellerDoesErrbackCalled']) self.assertEqual(False, nonlocal['cancellerDoesCallbackCalled']) # Cancel Question #2 h.handleQANFrame(Cancellation(2)) self.assertTrue(nonlocal['cancellerDoesErrbackCalled']) self.assertEqual([ KnownErrorAnswer("okay, you'll never know", 2), ], sent.getNew()) # Cancel Question #4 h.handleQANFrame(Cancellation(4)) self.assertTrue(nonlocal['cancellerDoesCallbackCalled']) self.assertEqual([ OkayAnswer("maybe a little warm", 4) ], sent.getNew()) # Cancel Question #1, which has no canceller h.handleQANFrame(Cancellation(1)) self.assertEqual([ UnknownErrorAnswer("CancelledError", 1), ], sent.getNew()) d3.errback(KnownError("weather station is broken")) self.assertEqual([ KnownErrorAnswer("weather station is broken", 3), ], sent.getNew())