Ticket #3462: t3462-3.diff

File t3462-3.diff, 5.7 KB (added by warner, 6 years ago)

new patch incorporating spiv's recommendations

  • twisted/test/test_ftp.py

     
    99
    1010import os
    1111import errno
     12from StringIO import StringIO
    1213
    1314from zope.interface import implements
    1415
     
    26162617
    26172618    def test_write(self):
    26182619        """
    2619         Test L{ftp.IWriteFile}: the implementation should have a receive method
    2620         returning a C{Deferred} with fires with a consumer ready to receive
    2621         data to be written.
     2620        Test L{ftp.IWriteFile}: the implementation should have a receive
     2621        method returning a C{Deferred} which fires with a consumer ready to
     2622        receive data to be written. It should also have a close() method that
     2623        returns a Deferred.
    26222624        """
    26232625        content = 'elbbow\n'
    26242626        def cbGet(writer):
    2625             return writer.receive().addCallback(cbReceive)
    2626         def cbReceive(consumer):
     2627            return writer.receive().addCallback(cbReceive, writer)
     2628        def cbReceive(consumer, writer):
    26272629            producer = TestProducer(content, consumer)
    26282630            consumer.registerProducer(None, True)
    26292631            producer.start()
    26302632            consumer.unregisterProducer()
     2633            return writer.close().addCallback(cbClose)
     2634        def cbClose(ignored):
    26312635            self.assertEquals(self.getFileContent(), content)
    26322636        return self.getFileWriter().addCallback(cbGet)
    26332637
     
    26692673        Return the content of the temporary file.
    26702674        """
    26712675        return self.root.child(self.filename).getContent()
     2676
     2677
     2678class CloseTestWriter:
     2679    implements(ftp.IWriteFile)
     2680    closeStarted = False
     2681    def receive(self):
     2682        self.s = StringIO()
     2683        fc = ftp.FileConsumer(self.s)
     2684        return defer.succeed(fc)
     2685    def close(self):
     2686        self.closeStarted = True
     2687        return self.d
     2688
     2689class CloseTestShell:
     2690    def openForWriting(self, segs):
     2691        return defer.succeed(self.writer)
     2692
     2693class FTPCloseTest(unittest.TestCase):
     2694    """Tests that the server invokes IWriteFile.close"""
     2695
     2696    def test_write(self):
     2697        """Confirm that FTP uploads (i.e. ftp_STOR) correctly call and wait
     2698        upon the IWriteFile object's close() method"""
     2699        f = ftp.FTP()
     2700        f.workingDirectory = ["root"]
     2701        f.shell = CloseTestShell()
     2702        f.shell.writer = CloseTestWriter()
     2703        f.shell.writer.d = defer.Deferred()
     2704        f.factory = ftp.FTPFactory()
     2705        f.factory.timeOut = None
     2706        f.makeConnection(StringIO())
     2707
     2708        di = ftp.DTP()
     2709        di.factory = ftp.DTPFactory(f)
     2710        f.dtpInstance = di
     2711        di.makeConnection(None)#
     2712
     2713        stor_done = []
     2714        d = f.ftp_STOR("path")
     2715        d.addCallback(stor_done.append)
     2716        # the writer is still receiving data
     2717        self.assertFalse(f.shell.writer.closeStarted, "close() called early")
     2718        di.dataReceived("some data here")
     2719        self.assertFalse(f.shell.writer.closeStarted, "close() called early")
     2720        di.connectionLost("reason is ignored")
     2721        # now we should be waiting in close()
     2722        self.assertTrue(f.shell.writer.closeStarted, "close() not called")
     2723        self.assertFalse(stor_done)
     2724        f.shell.writer.d.callback("allow close() to finish")
     2725        self.assertTrue(stor_done)
     2726
     2727        return d # just in case an errback occurred
  • twisted/protocols/ftp.py

     
    11221122                cons = ASCIIConsumerWrapper(cons)
    11231123
    11241124            d = self.dtpInstance.registerConsumer(cons)
    1125             d.addCallbacks(cbSent, ebSent)
    11261125
    11271126            # Tell them what to doooo
    11281127            if self.dtpInstance.isConnected:
     
    11351134        def cbOpened(file):
    11361135            d = file.receive()
    11371136            d.addCallback(cbConsumer)
     1137            d.addCallback(lambda ignored: file.close())
     1138            d.addCallbacks(cbSent, ebSent)
    11381139            return d
    11391140
    11401141        def ebOpened(err):
     
    15071508        @rtype: C{Deferred} of C{IConsumer}
    15081509        """
    15091510
     1511    def close():
     1512        """
     1513        Perform any post-write work that needs to be done. This method may
     1514        only be invoked once on each provider, and will always be invoked
     1515        after receive().
    15101516
     1517        @rtype: C{Deferred} of anything: the value is ignored. The FTP client
     1518        will not see their upload request complete until this Deferred has
     1519        been fired.
     1520        """
    15111521
    15121522def _getgroups(uid):
    15131523    """Return the primary and supplementary groups for the given UID.
     
    18681878        # FileConsumer will close the file object
    18691879        return defer.succeed(FileConsumer(self.fObj))
    18701880
     1881    def close(self):
     1882        return defer.succeed(None)
    18711883
    18721884
    18731885class FTPRealm:
  • twisted/vfs/adapters/ftp.py

     
    295295        """
    296296        return defer.succeed(IConsumer(self.node))
    297297
     298    def close(self):
     299        """
     300        Perform post-write actions.
     301        """
     302        return defer.succeed(None)
    298303
    299304
    300305class _FileToConsumerAdapter(object):
  • new file twisted/topfiles/3462.feature

    - +  
     1twisted.protocol.ftp.IWriteFile now has a close() method, which can return a
     2Deferred. Previously a STOR command would finish immediately upon the receipt
     3of the last byte of the uploaded file. With close(), the backend can delay
     4the finish until it has performed some other slow action (like storing the
     5data to a virtual filesystem).