Changeset 212
- Timestamp:
- 2003-03-15 21:22:31 (6 years ago)
- Files:
-
- trunk/_test_ftputil.py (modified) (5 diffs)
- trunk/ftputil.py (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/_test_ftputil.py
r206 r212 1 # Copyright (C) 200 2, Stefan Schwarzer1 # Copyright (C) 2003, Stefan Schwarzer 2 2 # All rights reserved. 3 3 # … … 30 30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 31 32 # $Id: _test_ftputil.py,v 1.6 3 2003/03/15 18:46:17schwa Exp $32 # $Id: _test_ftputil.py,v 1.64 2003/03/15 21:22:31 schwa Exp $ 33 33 34 34 import unittest … … 93 93 mock_file_content = binary_data() 94 94 95 class TimeShiftMockSession(_mock_ftplib.MockSession): 96 current_dir = '/login/dir' 97 98 def delete(self, file_name): 99 pass 100 95 101 96 102 # … … 99 105 class FailingUploadAndDownloadFTPHost(ftputil.FTPHost): 100 106 def upload(self, source, target, mode=''): 101 assert 0, " FTPHost.uploadshould not have been called"107 assert 0, "`FTPHost.upload` should not have been called" 102 108 103 109 def download(self, source, target, mode=''): 104 assert 0, "FTPHost.download should not have been called" 110 assert 0, "`FTPHost.download` should not have been called" 111 112 class TimeShiftFTPHost(ftputil.FTPHost): 113 class _Path: 114 def set_mtime(self, mtime): 115 self._mtime = mtime 116 def getmtime(self, file_name): 117 return self._mtime 118 119 def __init__(self, *args, **kwargs): 120 ftputil.FTPHost.__init__(self, *args, **kwargs) 121 self.path = self._Path() 105 122 106 123 … … 555 572 556 573 574 class TestTimeShift(unittest.TestCase): 575 def test_rounded_time_shift(self): 576 """Test if time shift is rounded correctly.""" 577 host = ftp_host_factory(session_factory=TimeShiftMockSession) 578 # use private bound method 579 rounded_time_shift = host._FTPHost__rounded_time_shift 580 # original value, expected result 581 test_data = [ 582 (0, 0), (0.1, 0), (-0.1, 0), (1500, 0), (-1500, 0), 583 (1800, 3600), (-1800, -3600), (2000, 3600), (-2000, -3600), 584 (5*3600-100, 5*3600), (-5*3600+100, -5*3600) ] 585 for time_shift, expected_time_shift in test_data: 586 calculated_time_shift = rounded_time_shift(time_shift) 587 self.assertEqual(calculated_time_shift, expected_time_shift) 588 589 def test_assert_valid_time_shift(self): 590 """Test time shift sanity checks.""" 591 host = ftp_host_factory(session_factory=TimeShiftMockSession) 592 # use private bound method 593 assert_time_shift = host._FTPHost__assert_valid_time_shift 594 # valid time shifts 595 test_data = [23*3600, -23*3600, 3600+30, -3600+30] 596 for time_shift in test_data: 597 self.failUnless( assert_time_shift(time_shift) is None ) 598 # invalid time shift (exceeds one day) 599 self.assertRaises(ftputil.TimeShiftError, assert_time_shift, 25*3600) 600 self.assertRaises(ftputil.TimeShiftError, assert_time_shift, -25*3600) 601 # invalid time shift (deviation from full hours unacceptable) 602 self.assertRaises(ftputil.TimeShiftError, assert_time_shift, 10*60) 603 self.assertRaises(ftputil.TimeShiftError, assert_time_shift, 604 -3600-10*60) 605 606 def test_synchronize_time(self): 607 """Test time synchronization with server.""" 608 host = ftp_host_factory(ftp_host_class=TimeShiftFTPHost, 609 session_factory=TimeShiftMockSession) 610 # valid time shift 611 host.path.set_mtime( time.time() + 3630 ) 612 host.synchronize_time() 613 self.assertEqual( host.time_shift(), 3600 ) 614 # invalid time shift 615 host.path.set_mtime( time.time() + 3600+10*60 ) 616 self.assertRaises(ftputil.TimeShiftError, host.synchronize_time) 617 618 557 619 if __name__ == '__main__': 558 620 unittest.main() trunk/ftputil.py
r210 r212 30 30 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 31 32 # $Id: ftputil.py,v 1.10 2 2003/03/15 18:57:22schwa Exp $32 # $Id: ftputil.py,v 1.103 2003/03/15 21:22:31 schwa Exp $ 33 33 34 34 """ … … 128 128 129 129 class RootDirError(FTPError): pass 130 class TimeShiftError(FTPError): pass 130 131 131 132 class FTPOSError(FTPError, OSError): pass … … 392 393 # servers 393 394 self.curdir, self.pardir, self.sep = '.', '..', '/' 395 # set default time shift (used in `upload_if_newer` and 396 # `download_if_newer`) 397 self.set_time_shift(0.0) 394 398 # check if we have a Microsoft ROBIN server 395 399 try: … … 481 485 # we don't want warnings if the constructor did fail 482 486 pass 487 488 # 489 # time shift adjustment between client (i. e. us) and server 490 # 491 def set_time_shift(self, time_shift): 492 """ 493 Set the time shift value (i. e. the time difference between 494 client and server) for this `FTPHost` object. By definition, 495 the time shift value is positive if the local time of the 496 server is greater than the local time of the client. The 497 time shift is measured in seconds. 498 """ 499 self._time_shift = time_shift 500 501 def time_shift(self): 502 """ 503 Return the time shift between FTP server and client. See the 504 docstring of `set_time_shift` for more on this value. 505 """ 506 return self._time_shift 507 508 def __rounded_time_shift(self, time_shift): 509 """ 510 Return the given time shift in seconds, but rounded to 511 full hours. The argument is also assumed to be given in 512 seconds. 513 """ 514 minute = 60.0 515 hour = 60 * minute 516 # avoid division by zero below 517 if time_shift == 0: 518 return 0.0 519 # use a positive value for rounding 520 absolute_time_shift = abs(time_shift) 521 signum = time_shift / absolute_time_shift 522 # round it to hours; this code should also work for later Python 523 # versions because of the explicit `int` 524 absolute_rounded_time_shift = \ 525 int( (absolute_time_shift+30*minute) / hour) * hour 526 # return with correct sign 527 return signum * absolute_rounded_time_shift 528 529 def __assert_valid_time_shift(self, time_shift): 530 """ 531 Perform sanity checks on the time shift value (given in 532 seconds). If the value fails, raise a `TimeShiftError`, 533 else simply return `None`. 534 """ 535 minute = 60.0 536 hour = 60 * minute 537 absolute_rounded_time_shift = \ 538 abs( self.__rounded_time_shift(time_shift) ) 539 # test 1: fail if the absolute time shift is greater than 540 # a full day (24 hours) 541 if absolute_rounded_time_shift > 24 * hour: 542 raise TimeShiftError( 543 "time shift (%.2f s) > 1 day" % time_shift) 544 # test 2: fail if the deviation between given time shift and 545 # full hours is greater than a certain limit (e. g. five minutes) 546 maximum_deviation = 5 * minute 547 if abs( time_shift - self.__rounded_time_shift(time_shift) ) > \ 548 maximum_deviation: 549 raise TimeShiftError( 550 "time shift (%.2f s) deviates more than %d s from full hours" 551 % (time_shift, maximum_deviation) ) 552 553 def synchronize_time(self): 554 """ 555 Synchronize the local times of FTP client and server. This 556 is necessary to let `upload_if_newer` and `download_if_newer` 557 work correctly. 558 559 This implementation of `synchronize_time` requires all of the 560 following: 561 - The connection between server and client is established. 562 - The client has write access to the directory that is 563 current when `synchronize_time` is called. 564 - That directory isn't the root directory of the FTP server. 565 566 The usual usage pattern of `synchronize_time` is to call it 567 directly after the connection is established. (As can be 568 concluded from the points above, this requires write access 569 to the login directory.) 570 571 If `synchronize_time` fails, it raises a `TimeShiftError`. 572 """ 573 helper_file_name = "_ftputil_sync_" 574 # open a dummy file for writing in the current directory 575 # on the FTP host, then close it 576 try: 577 file_ = self.file(helper_file_name, 'w') 578 file_.close() 579 # get the modification time of the new file 580 try: 581 modification_time = self.path.getmtime(helper_file_name) 582 except RootDirError: 583 raise TimeShiftError("can't use root directory for temp file") 584 finally: 585 # remove the just written file 586 self.unlink(helper_file_name) 587 # calculate the difference between server and client 588 time_shift = modification_time - time.time() 589 # do some sanity checks 590 self.__assert_valid_time_shift(time_shift) 591 # if tests passed, store the time difference as time shift value 592 self.set_time_shift( self.__rounded_time_shift(time_shift) ) 483 593 484 594 #
