immutable repairer: errback any pending readers of DownUpConnectorwhen it runs out of bytes, and test that fact

This commit is contained in:
Zooko O'Whielacronx 2009-02-11 20:11:29 -07:00
parent 125bf09528
commit 76d7cc4404
2 changed files with 29 additions and 1 deletions

View File

@ -73,6 +73,16 @@ class Repairer(log.PrefixingLogMixin):
return d return d
class PrematureClose(Exception):
# Uploader asked DUC to read a certain number of bytes, and
# Downloader closed DUC before writing enough bytes to satisfy the
# read.
def __init__(self, requested, avail):
self.requested = requested
self.avail = avail
def __repr__(self):
return "<%s requested: %d, avail: %d>" % (self.__class__.__name__, self.requested, self.avail)
class DownUpConnector(log.PrefixingLogMixin): class DownUpConnector(log.PrefixingLogMixin):
implements(IEncryptedUploadable, IDownloadTarget, IConsumer) implements(IEncryptedUploadable, IDownloadTarget, IConsumer)
""" I act like an "encrypted uploadable" -- something that a local uploader can read """ I act like an "encrypted uploadable" -- something that a local uploader can read
@ -174,6 +184,10 @@ class DownUpConnector(log.PrefixingLogMixin):
pass pass
def close(self): def close(self):
self._closed_to_pusher = True self._closed_to_pusher = True
# Any reads which haven't been satisfied by now are not going to be satisfied.
while self.next_read_ds:
self.next_read_ds.popleft().errback(
PrematureClose(self.next_read_lens.popleft(), self.bufsiz))
# methods to satisfy the IEncryptedUploader interface # methods to satisfy the IEncryptedUploader interface
# (From the perspective of an uploader I am an IEncryptedUploadable.) # (From the perspective of an uploader I am an IEncryptedUploadable.)

View File

@ -353,7 +353,7 @@ class DownUpConnector(unittest.TestCase):
duc.write('\x02') duc.write('\x02')
return d return d
def test_leftovers(self): def test_extra(self):
duc = repairer.DownUpConnector() duc = repairer.DownUpConnector()
duc.registerProducer(None, True) # just because you have to call registerProducer first duc.registerProducer(None, True) # just because you have to call registerProducer first
# case 1: total data in buf is < requested data at time of request # case 1: total data in buf is < requested data at time of request
@ -367,6 +367,20 @@ class DownUpConnector(unittest.TestCase):
duc.write('\x02\0x03') duc.write('\x02\0x03')
return d return d
def test_premature_close(self):
duc = repairer.DownUpConnector()
duc.registerProducer(None, True) # just because you have to call registerProducer first
d = duc.read_encrypted(2, False)
duc.close()
def _callb(f):
self.fail("Should have errbacked.")
def _errb(f):
f.trap(repairer.PrematureClose)
self.failUnlessEqual(f.value.requested, 2)
# Okay, you pass the test.
d.addCallbacks(_callb, _errb)
return d
class Repairer(common.ShareManglingMixin, unittest.TestCase): class Repairer(common.ShareManglingMixin, unittest.TestCase):
def test_test_code(self): def test_test_code(self):
# The following process of stashing the shares, running # The following process of stashing the shares, running