Ticket #3462: t3462-3.diff

File t3462-3.diff, 5.7 KB (added by warner, 4 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).