Index: twisted/test/test_ftp.py
===================================================================
--- twisted/test/test_ftp.py	(revision 34534)
+++ twisted/test/test_ftp.py	(working copy)
@@ -81,9 +81,19 @@
         self.dirPath = filepath.FilePath(self.directory)
 
         # Start the server
-        p = portal.Portal(ftp.FTPRealm(self.directory))
+        p = portal.Portal(ftp.FTPRealm(
+            anonymousRoot=self.directory,
+            userHome=self.directory,
+            ))
         p.registerChecker(checkers.AllowAnonymousAccess(),
                           credentials.IAnonymous)
+
+        users_checker = checkers.InMemoryUsernamePasswordDatabaseDontUse()
+        self.username = "test-user"
+        self.password = "test-password"
+        users_checker.addUser(self.username, self.password)
+        p.registerChecker(users_checker, credentials.IUsernamePassword)
+
         self.factory = ftp.FTPFactory(portal=p,
                                       userAnonymous=self.userAnonymous)
         port = reactor.listenTCP(0, self.factory, interface="127.0.0.1")
@@ -159,6 +169,15 @@
             ['230 Anonymous login ok, access restrictions apply.'],
             chainDeferred=d)
 
+    def _userLogin(self):
+        """Authenticates the FTP client using the test account."""
+        d = self.assertCommandResponse(
+            'USER %s' % (self.username),
+            ['331 Password required for %s.' % (self.username)])
+        return self.assertCommandResponse(
+            'PASS %s' % (self.password),
+            ['230 User logged in, proceed'],
+            chainDeferred=d)
 
 
 class FTPAnonymousTestCase(FTPServerTestCase):
@@ -342,13 +361,57 @@
         self.serverProtocol.transport.loseConnection()
     testPASV = defer.deferredGenerator(testPASV)
 
-    def testSYST(self):
+    def test_SYST(self):
+        """SYST command will always return UNIX Type: L8"""
         d = self._anonymousLogin()
         self.assertCommandResponse('SYST', ["215 UNIX Type: L8"],
                                    chainDeferred=d)
         return d
 
+    def test_RNFRandRNTO(self):
+        """
+        Sending the RNFR command followed by RNTO should perfrom a
+        successful rename operation.
+        """
+        # Create user home folder with a 'foo' file.
+        self.dirPath.child(self.username).createDirectory()
+        self.dirPath.child(self.username).child('foo').touch()
 
+        d = self._userLogin()
+        self.assertCommandResponse(
+            'RNFR foo',
+            ["350 Requested file action pending further information."],
+            chainDeferred=d)
+        self.assertCommandResponse(
+            'RNTO bar',
+            ["250 Requested File Action Completed OK"],
+            chainDeferred=d)
+
+        def check_rename(result):
+            self.assertTrue(
+                self.dirPath.child(self.username).child('bar').exists())
+            return result
+
+        d.addCallback(check_rename)
+        return d
+
+    def test_RNFRwithoutRNTO(self):
+        """
+        Sending the RNFR command followed by any command other than RNTO
+        should return an error informing users that RNFR should be followd
+        by RNTO.
+        """
+        d = self._anonymousLogin()
+        self.assertCommandResponse(
+            'RNFR foo',
+            ["350 Requested file action pending further information."],
+            chainDeferred=d)
+        self.assertCommandFailed(
+            'OTHER don-tcare',
+            ["503 Incorrect sequence of commands: RNTO required after RNFR"],
+            chainDeferred=d)
+        return d
+
     def test_portRangeForwardError(self):
         """
         Exceptions other than L{error.CannotListenError} which are raised by
