duplicity-team team mailing list archive
-
duplicity-team team
-
Mailing list archive
-
Message #02143
[Merge] lp:~mterry/duplicity/more-test-reorg into lp:duplicity
Michael Terry has proposed merging lp:~mterry/duplicity/more-test-reorg into lp:duplicity.
Requested reviews:
duplicity-team (duplicity-team)
For more details, see:
https://code.launchpad.net/~mterry/duplicity/more-test-reorg/+merge/216545
Here's another test reorganization / modernization branch. It does the following things:
- Drop duplicity/misc.py. It is confusing to have both misc.py and util.py, and most of the code in misc.py was no longer used. I moved the one function that was still used into util.py.
- Consolidated the various ways to run tests into just one. I made tox runs go through ./setup.py test, rather than nosetests. And I made the ./testing/run-tests scripts just call tox. Now we no longer need nosetests as a test dependency (although you can still use it if you want).
- Added two more code quality automated tests: a pep8 one and a pylint one. I disabled almost all checks in each program that gave a warning. These tests just establish a baseline for future improvement.
- Moved the test helper code into TestCase subclasses that all tests can use. And used more code sharing and setUp/tearDown cleverness to remove duplicated code.
- Reorganized the tests in ./testing/tests into ./testing/functional and ./testing/unit -- for whether they drive duplicity as a subprocess or whether they import and test code directly. Each dir can have specialized TestCase subclasses now.
- Renamed the files in ./testing/unit to more clearly indicate which file in ./duplicity they are unit testing.
- Added some helper methods for tests to set environment and globals.* parameters more safely (i.e. without affecting other tests) by automatically cleaning up any such changes during test tearDown.
- Removed test_unicode.py, since it is kind of dumb. It used to be more useful, but now with py2.6, we are just testing that one line of code in it is actually there.
--
https://code.launchpad.net/~mterry/duplicity/more-test-reorg/+merge/216545
Your team duplicity-team is requested to review the proposed merge of lp:~mterry/duplicity/more-test-reorg into lp:duplicity.
=== modified file 'duplicity/backend.py'
--- duplicity/backend.py 2014-04-17 20:50:57 +0000
+++ duplicity/backend.py 2014-04-20 14:58:57 +0000
@@ -355,7 +355,7 @@
return _retry_fatal
-class Backend:
+class Backend(object):
"""
Represents a generic duplicity backend, capable of storing and
retrieving files.
=== modified file 'duplicity/gpg.py'
--- duplicity/gpg.py 2014-04-17 21:13:48 +0000
+++ duplicity/gpg.py 2014-04-20 14:58:57 +0000
@@ -27,10 +27,10 @@
import os, types, tempfile, re, gzip, locale
-from duplicity import misc
from duplicity import globals
from duplicity import gpginterface
from duplicity import tempdir
+from duplicity import util
try:
from hashlib import sha1
@@ -313,7 +313,7 @@
>> largest block size).
"""
incompressible_fp = open(filename, "rb")
- assert misc.copyfileobj(incompressible_fp, file.gpg_input, bytes) == bytes
+ assert util.copyfileobj(incompressible_fp, file.gpg_input, bytes) == bytes
incompressible_fp.close()
def get_current_size():
=== removed file 'duplicity/misc.py'
--- duplicity/misc.py 2013-12-27 06:39:00 +0000
+++ duplicity/misc.py 1970-01-01 00:00:00 +0000
@@ -1,192 +0,0 @@
-# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
-#
-# Copyright 2002 Ben Escoto <ben@xxxxxxxxxxx>
-# Copyright 2007 Kenneth Loafman <kenneth@xxxxxxxxxxx>
-#
-# This file is part of duplicity.
-#
-# Duplicity is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# Duplicity is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with duplicity; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-"""Miscellaneous classes and methods"""
-
-import os
-
-from duplicity import log
-from duplicity import util
-
-
-class MiscError(Exception):
- """Signifies a miscellaneous error..."""
- pass
-
-
-class FileVolumeWriter:
- """Split up an incoming fileobj into multiple volumes on disk
-
- This class can also be used as an iterator. It returns the
- filenames of the files it writes.
-
- """
- volume_size = 50 * 1024 * 1024
- blocksize = 64 * 1024
- def __init__(self, infp, file_prefix):
- """FileVolumeWriter initializer
-
- infp is a file object opened for reading. It will be closed
- at end. file_prefix is the full path of the volumes that will
- be written. If more than one is required, it will be appended
- with .1, .2, etc.
-
- """
- self.infp = infp
- self.prefix = file_prefix
- self.current_index = 1
- self.finished = None # set to true when completely done
- self.buffer = "" # holds data that belongs in next volume
-
- def get_initial_buf(self):
- """Get first value of buffer, from self.buffer or infp"""
- if self.buffer:
- buf = self.buffer
- self.buffer = ""
- return buf
- else:
- return self.infp.read(self.blocksize)
-
- def write_volume(self, outfp):
- """Write self.volume_size bytes from self.infp to outfp
-
- Return None if we have reached end of infp without reaching
- volume size, and false otherwise.
-
- """
- bytes_written, buf = 0, self.get_initial_buf()
- while len(buf) + bytes_written <= self.volume_size:
- if not buf:
- # reached end of input
- outfp.close()
- return None
- if len(buf) + bytes_written > self.volume_size:
- break
- outfp.write(buf)
- bytes_written += len(buf)
- buf = self.infp.read(self.blocksize)
-
- remainder = self.volume_size - bytes_written
- assert remainder < len(buf)
- outfp.write(buf[:remainder])
- outfp.close()
- self.buffer = buf[remainder:]
- return 1
-
- def next(self):
- """Write next file, return filename"""
- if self.finished:
- raise StopIteration
-
- filename = "%s.%d" % (self.prefix, self.current_index)
- log.Info(_("Starting to write %s") % util.ufn(filename))
- outfp = open(filename, "wb")
-
- if not self.write_volume(outfp):
- # end of input
- self.finished = 1
- if self.current_index == 1:
- # special case first index
- log.Notice(_("One only volume required.\n"
- "Renaming %s to %s") % (util.ufn(filename), util.ufn(self.prefix)))
- os.rename(filename, self.prefix)
- return self.prefix
- else:
- self.current_index += 1
- return filename
-
- def __iter__(self):
- return self
-
-
-class BufferedFile:
- """Buffer file open for reading, so reads will happen in fixed sizes
-
- This is currently used to buffer a GzipFile, because that class
- apparently doesn't respond well to arbitrary read sizes.
-
- """
- def __init__(self, fileobj, blocksize = 32 * 1024):
- self.fileobj = fileobj
- self.buffer = ""
- self.blocksize = blocksize
-
- def read(self, length = -1):
- """Return length bytes, or all if length < 0"""
- if length < 0:
- while 1:
- buf = self.fileobj.read(self.blocksize)
- if not buf:
- break
- self.buffer += buf
- real_length = len(self.buffer)
- else:
- while len(self.buffer) < length:
- buf = self.fileobj.read(self.blocksize)
- if not buf:
- break
- self.buffer += buf
- real_length = min(length, len(self.buffer))
- result = self.buffer[:real_length]
- self.buffer = self.buffer[real_length:]
- return result
-
- def close(self):
- self.fileobj.close()
-
-
-def copyfileobj(infp, outfp, byte_count = -1):
- """Copy byte_count bytes from infp to outfp, or all if byte_count < 0
-
- Returns the number of bytes actually written (may be less than
- byte_count if find eof. Does not close either fileobj.
-
- """
- blocksize = 64 * 1024
- bytes_written = 0
- if byte_count < 0:
- while 1:
- buf = infp.read(blocksize)
- if not buf:
- break
- bytes_written += len(buf)
- outfp.write(buf)
- else:
- while bytes_written + blocksize <= byte_count:
- buf = infp.read(blocksize)
- if not buf:
- break
- bytes_written += len(buf)
- outfp.write(buf)
- buf = infp.read(byte_count - bytes_written)
- bytes_written += len(buf)
- outfp.write(buf)
- return bytes_written
-
-def copyfileobj_close(infp, outfp):
- """Copy infp to outfp, closing afterwards"""
- copyfileobj(infp, outfp)
- if infp.close():
- raise MiscError("Error closing input file")
- if outfp.close():
- raise MiscError("Error closing output file")
-
-
=== modified file 'duplicity/patchdir.py'
--- duplicity/patchdir.py 2014-04-17 20:50:57 +0000
+++ duplicity/patchdir.py 2014-04-20 14:58:57 +0000
@@ -28,7 +28,6 @@
from duplicity import librsync #@UnusedImport
from duplicity import log #@UnusedImport
from duplicity import diffdir
-from duplicity import misc
from duplicity import selection
from duplicity import tempdir
from duplicity import util #@UnusedImport
@@ -478,7 +477,7 @@
by using the duplicity.tempdir to tell us where.
"""
tempfp = tempfile.TemporaryFile( dir=tempdir.default().dir() )
- misc.copyfileobj( current_file, tempfp )
+ util.copyfileobj( current_file, tempfp )
assert not current_file.close()
tempfp.seek( 0 )
current_file = tempfp
=== modified file 'duplicity/progress.py'
--- duplicity/progress.py 2014-04-17 21:46:00 +0000
+++ duplicity/progress.py 2014-04-20 14:58:57 +0000
@@ -32,7 +32,9 @@
This is a forecast based on gathered evidence.
"""
+from __future__ import absolute_import
+import collections as sys_collections
import math
import threading
import time
@@ -42,30 +44,6 @@
import pickle
import os
-def import_non_local(name, custom_name=None):
- """
- This function is needed to play a trick... as there exists a local
- "collections" module, that is named the same as a system module
- """
- import imp, sys
-
- custom_name = custom_name or name
-
- f, pathname, desc = imp.find_module(name, sys.path[1:])
- module = imp.load_module(custom_name, f, pathname, desc)
- f.close()
-
- return module
-
-"""
-Import non-local module, use a custom name to differentiate it from local
-This name is only used internally for identifying the module. We decide
-the name in the local scope by assigning it to the variable sys_collections.
-"""
-sys_collections = import_non_local('collections','sys_collections')
-
-
-
tracker = None
progress_thread = None
=== modified file 'duplicity/tempdir.py'
--- duplicity/tempdir.py 2014-04-17 22:03:10 +0000
+++ duplicity/tempdir.py 2014-04-20 14:58:57 +0000
@@ -54,7 +54,7 @@
_defaultLock.acquire()
try:
- if _defaultInstance is None:
+ if _defaultInstance is None or _defaultInstance.dir() is None:
_defaultInstance = TemporaryDirectory(temproot = globals.temproot)
return _defaultInstance
finally:
=== modified file 'duplicity/util.py'
--- duplicity/util.py 2014-04-17 20:50:57 +0000
+++ duplicity/util.py 2014-04-20 14:58:57 +0000
@@ -145,3 +145,30 @@
except UnlockError:
pass
+def copyfileobj(infp, outfp, byte_count = -1):
+ """Copy byte_count bytes from infp to outfp, or all if byte_count < 0
+
+ Returns the number of bytes actually written (may be less than
+ byte_count if find eof. Does not close either fileobj.
+
+ """
+ blocksize = 64 * 1024
+ bytes_written = 0
+ if byte_count < 0:
+ while 1:
+ buf = infp.read(blocksize)
+ if not buf:
+ break
+ bytes_written += len(buf)
+ outfp.write(buf)
+ else:
+ while bytes_written + blocksize <= byte_count:
+ buf = infp.read(blocksize)
+ if not buf:
+ break
+ bytes_written += len(buf)
+ outfp.write(buf)
+ buf = infp.read(byte_count - bytes_written)
+ bytes_written += len(buf)
+ outfp.write(buf)
+ return bytes_written
=== modified file 'po/POTFILES.in'
--- po/POTFILES.in 2014-04-18 14:32:30 +0000
+++ po/POTFILES.in 2014-04-20 14:58:57 +0000
@@ -15,7 +15,6 @@
duplicity/collections.py
duplicity/log.py
duplicity/robust.py
-duplicity/misc.py
duplicity/diffdir.py
duplicity/lazy.py
duplicity/backends/_cf_pyrax.py
=== modified file 'setup.py'
--- setup.py 2014-04-17 19:34:23 +0000
+++ setup.py 2014-04-20 14:58:57 +0000
@@ -79,7 +79,7 @@
# make symlinks for test data
if build_cmd.build_lib != top_dir:
- for path in ['testfiles.tar.gz', 'testtar.tar', 'gnupg']:
+ for path in ['testfiles.tar.gz', 'gnupg']:
src = os.path.join(top_dir, 'testing', path)
target = os.path.join(build_cmd.build_lib, 'testing', path)
try:
@@ -133,8 +133,9 @@
packages = ['duplicity',
'duplicity.backends',
'testing',
- 'testing.helpers',
- 'testing.tests'],
+ 'testing.functional',
+ 'testing.overrides',
+ 'testing.unit'],
package_dir = {"duplicity" : "duplicity",
"duplicity.backends" : "duplicity/backends",},
ext_modules = [Extension("duplicity._librsync",
@@ -144,8 +145,8 @@
libraries=["rsync"])],
scripts = ['bin/rdiffdir', 'bin/duplicity'],
data_files = data_files,
- tests_require = ['lockfile', 'mock', 'nose', 'pexpect'],
- test_suite = 'nose.collector',
+ tests_require = ['lockfile', 'mock', 'pexpect'],
+ test_suite = 'testing',
cmdclass={'test': TestCommand,
'install': InstallCommand,
'sdist': SDistCommand},
=== removed file 'testing/__init__.py'
=== renamed file 'testing/tests/__init__.py' => 'testing/__init__.py'
--- testing/tests/__init__.py 2014-04-16 20:45:09 +0000
+++ testing/__init__.py 2014-04-20 14:58:57 +0000
@@ -21,18 +21,21 @@
import os
import sys
import time
-
-_this_dir = os.path.dirname(os.path.abspath(__file__))
-_testing_dir = os.path.dirname(_this_dir)
+import unittest
+
+from duplicity import backend
+from duplicity import globals
+from duplicity import log
+
+_testing_dir = os.path.dirname(os.path.abspath(__file__))
_top_dir = os.path.dirname(_testing_dir)
-_helpers_dir = os.path.join(_testing_dir, 'helpers')
_overrides_dir = os.path.join(_testing_dir, 'overrides')
-# Adjust python path for duplicity and helper modules
-sys.path = [_overrides_dir, _top_dir, _helpers_dir] + sys.path
+# Adjust python path for duplicity and override modules
+sys.path = [_overrides_dir, _top_dir] + sys.path
# Also set PYTHONPATH for any subprocesses
-os.environ['PYTHONPATH'] = _overrides_dir + ":" + _top_dir
+os.environ['PYTHONPATH'] = _overrides_dir + ":" + _top_dir + ":" + os.environ.get('PYTHONPATH', '')
# Now set some variables that help standardize test behavior
os.environ['LANG'] = ''
@@ -41,3 +44,55 @@
# Standardize time
os.environ['TZ'] = 'US/Central'
time.tzset()
+
+
+class DuplicityTestCase(unittest.TestCase):
+
+ sign_key = '56538CCF'
+ sign_passphrase = 'test'
+ encrypt_key1 = 'B5FA894F'
+ encrypt_key2 = '9B736B2A'
+
+ def setUp(self):
+ super(DuplicityTestCase, self).setUp()
+ self.savedEnviron = {}
+ self.savedGlobals = {}
+
+ # TODO: remove these lines
+ log.setup()
+ log.setverbosity(log.WARNING)
+ self.set_global('print_statistics', 0)
+ backend.import_backends()
+
+ # Have all file references in tests relative to our testing dir
+ os.chdir(_testing_dir)
+
+ def tearDown(self):
+ for key in self.savedEnviron:
+ self._update_env(key, self.savedEnviron[key])
+ for key in self.savedGlobals:
+ setattr(globals, key, self.savedGlobals[key])
+ assert not os.system("rm -rf testfiles")
+ super(DuplicityTestCase, self).tearDown()
+
+ def unpack_testfiles(self):
+ assert not os.system("rm -rf testfiles")
+ assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
+ assert not os.system("mkdir testfiles/output testfiles/cache")
+
+ def _update_env(self, key, value):
+ if value is not None:
+ os.environ[key] = value
+ elif key in os.environ:
+ del os.environ[key]
+
+ def set_environ(self, key, value):
+ if key not in self.savedEnviron:
+ self.savedEnviron[key] = os.environ.get(key)
+ self._update_env(key, value)
+
+ def set_global(self, key, value):
+ assert hasattr(globals, key)
+ if key not in self.savedGlobals:
+ self.savedGlobals[key] = getattr(globals, key)
+ setattr(globals, key, value)
=== added directory 'testing/functional'
=== added file 'testing/functional/__init__.py'
--- testing/functional/__init__.py 1970-01-01 00:00:00 +0000
+++ testing/functional/__init__.py 2014-04-20 14:58:57 +0000
@@ -0,0 +1,147 @@
+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
+#
+# Copyright 2012 Canonical Ltd
+#
+# This file is part of duplicity.
+#
+# Duplicity is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# Duplicity is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with duplicity; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import os
+import pexpect
+import time
+import unittest
+
+from duplicity import backend
+from .. import DuplicityTestCase
+
+
+class CmdError(Exception):
+ """Indicates an error running an external command"""
+ def __init__(self, code):
+ Exception.__init__(self, code)
+ self.exit_status = code
+
+
+class FunctionalTestCase(DuplicityTestCase):
+
+ def setUp(self):
+ super(FunctionalTestCase, self).setUp()
+
+ self.unpack_testfiles()
+
+ self.class_args = []
+ self.backend_url = "file://testfiles/output"
+ self.last_backup = None
+ self.set_environ('PASSPHRASE', self.sign_passphrase)
+ self.set_environ("SIGN_PASSPHRASE", self.sign_passphrase)
+
+ backend_inst = backend.get_backend(self.backend_url)
+ bl = backend_inst.list()
+ if bl:
+ backend_inst.delete(backend_inst.list())
+ backend_inst.close()
+
+ def run_duplicity(self, options=[], current_time=None, fail=None,
+ passphrase_input=[]):
+ """
+ Run duplicity binary with given arguments and options
+ """
+ # We run under setsid and take input from /dev/null (below) because
+ # this way we force a failure if duplicity tries to read from the
+ # console unexpectedly (like for gpg password or such).
+ cmd_list = ["setsid", "duplicity"]
+ cmd_list.extend(options)
+ cmd_list.extend(["-v0"])
+ cmd_list.extend(["--no-print-statistics"])
+ cmd_list.extend(["--allow-source-mismatch"])
+ cmd_list.extend(["--archive-dir=testfiles/cache"])
+ if current_time:
+ cmd_list.extend(["--current-time", current_time])
+ cmd_list.extend(self.class_args)
+ if fail:
+ cmd_list.extend(["--fail", str(fail)])
+ cmdline = " ".join(map(lambda x: '"%s"' % x, cmd_list))
+
+ if not passphrase_input:
+ cmdline += " < /dev/null"
+ child = pexpect.spawn('/bin/sh', ['-c', cmdline])
+ for passphrase in passphrase_input:
+ child.expect('passphrase.*:')
+ child.sendline(passphrase)
+ child.wait()
+ return_val = child.exitstatus
+
+ #print "Ran duplicity command: ", cmdline, "\n with return_val: ", child.exitstatus
+ if fail:
+ self.assertEqual(30, child.exitstatus)
+ elif return_val:
+ raise CmdError(child.exitstatus)
+
+ def backup(self, type, input_dir, options=[], **kwargs):
+ """Run duplicity backup to default directory"""
+ options = [type, input_dir, self.backend_url, "--volsize", "1"] + options
+ before_files = self.get_backend_files()
+
+ # If a chain ends with time X and the next full chain begins at time X,
+ # we may trigger an assert in collections.py. If needed, sleep to
+ # avoid such problems
+ if self.last_backup == int(time.time()):
+ time.sleep(1)
+
+ result = self.run_duplicity(options=options, **kwargs)
+ self.last_backup = int(time.time())
+
+ after_files = self.get_backend_files()
+ return after_files - before_files
+
+ def restore(self, file_to_restore=None, time=None, options=[], **kwargs):
+ assert not os.system("rm -rf testfiles/restore_out")
+ options = [self.backend_url, "testfiles/restore_out"] + options
+ if file_to_restore:
+ options.extend(['--file-to-restore', file_to_restore])
+ if time:
+ options.extend(['--restore-time', str(time)])
+ self.run_duplicity(options=options, **kwargs)
+
+ def verify(self, dirname, file_to_verify=None, time=None, options=[],
+ **kwargs):
+ options = ["verify", self.backend_url, dirname] + options
+ if file_to_verify:
+ options.extend(['--file-to-restore', file_to_verify])
+ if time:
+ options.extend(['--restore-time', str(time)])
+ self.run_duplicity(options=options, **kwargs)
+
+ def cleanup(self, options=[]):
+ """
+ Run duplicity cleanup to default directory
+ """
+ options = ["cleanup", self.backend_url, "--force"] + options
+ self.run_duplicity(options=options)
+
+ def get_backend_files(self):
+ backend_inst = backend.get_backend(self.backend_url)
+ bl = backend_inst.list()
+ backend_inst.close()
+ return set(bl)
+
+ def make_largefiles(self, count=3, size=2):
+ """
+ Makes a number of large files in testfiles/largefiles that each are
+ the specified number of megabytes.
+ """
+ assert not os.system("mkdir testfiles/largefiles")
+ for n in range(count):
+ assert not os.system("dd if=/dev/urandom of=testfiles/largefiles/file%d bs=1024 count=%d > /dev/null 2>&1" % (n + 1, size * 1024))
=== renamed file 'testing/tests/test_badupload.py' => 'testing/functional/test_badupload.py'
--- testing/tests/test_badupload.py 2014-04-17 20:50:57 +0000
+++ testing/functional/test_badupload.py 2014-04-20 14:58:57 +0000
@@ -22,10 +22,10 @@
import unittest
-from helper import CmdError, DuplicityTestCase
-
-
-class BadUploadTest(DuplicityTestCase):
+from . import CmdError, FunctionalTestCase
+
+
+class BadUploadTest(FunctionalTestCase):
"""
Test missing volume upload using duplicity binary
"""
=== renamed file 'testing/tests/test_cleanup.py' => 'testing/functional/test_cleanup.py'
--- testing/tests/test_cleanup.py 2014-04-16 02:43:43 +0000
+++ testing/functional/test_cleanup.py 2014-04-20 14:58:57 +0000
@@ -21,10 +21,10 @@
import unittest
-from helper import DuplicityTestCase
-
-
-class CleanupTest(DuplicityTestCase):
+from . import FunctionalTestCase
+
+
+class CleanupTest(FunctionalTestCase):
"""
Test cleanup using duplicity binary
"""
=== renamed file 'testing/tests/test_final.py' => 'testing/functional/test_final.py'
--- testing/tests/test_final.py 2014-04-16 02:43:43 +0000
+++ testing/functional/test_final.py 2014-04-20 14:58:57 +0000
@@ -23,10 +23,10 @@
import unittest
from duplicity import path
-from helper import CmdError, DuplicityTestCase
-
-
-class FinalTest(DuplicityTestCase):
+from . import CmdError, FunctionalTestCase
+
+
+class FinalTest(FunctionalTestCase):
"""
Test backup/restore using duplicity binary
"""
@@ -165,17 +165,17 @@
class OldFilenamesFinalTest(FinalTest):
- @classmethod
- def setUpClass(cls):
- super(OldFilenamesFinalTest, cls).setUpClass()
- cls.class_args.extend(["--old-filenames"])
+
+ def setUp(self):
+ super(OldFilenamesFinalTest, self).setUp()
+ self.class_args.extend(["--old-filenames"])
class ShortFilenamesFinalTest(FinalTest):
- @classmethod
- def setUpClass(cls):
- super(ShortFilenamesFinalTest, cls).setUpClass()
- cls.class_args.extend(["--short-filenames"])
+
+ def setUp(self):
+ super(ShortFilenamesFinalTest, self).setUp()
+ self.class_args.extend(["--short-filenames"])
if __name__ == "__main__":
unittest.main()
=== renamed file 'testing/tests/test_log.py' => 'testing/functional/test_log.py'
--- testing/tests/test_log.py 2014-04-16 02:43:43 +0000
+++ testing/functional/test_log.py 2014-04-20 14:58:57 +0000
@@ -21,14 +21,19 @@
import unittest
import os
-class LogTest(unittest.TestCase):
+from . import FunctionalTestCase
+
+
+class LogTest(FunctionalTestCase):
"""Test machine-readable functions/classes in log.py"""
def setUp(self):
+ super(LogTest, self).setUp()
assert not os.system("rm -f /tmp/duplicity.log")
def tearDown(self):
assert not os.system("rm -f /tmp/duplicity.log")
+ super(LogTest, self).tearDown()
def test_command_line_error(self):
"""Check notification of a simple error code"""
=== renamed file 'testing/tests/test_rdiffdir.py' => 'testing/functional/test_rdiffdir.py'
--- testing/tests/test_rdiffdir.py 2014-04-16 02:43:43 +0000
+++ testing/functional/test_rdiffdir.py 2014-04-20 14:58:57 +0000
@@ -19,29 +19,18 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
-import sys, unittest, os
+import unittest, os
from duplicity import path
-
-helper.setup()
-
-class RdiffdirTest(unittest.TestCase):
+from . import FunctionalTestCase
+
+
+class RdiffdirTest(FunctionalTestCase):
"""Test rdiffdir command line program"""
- def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
def run_cmd(self, command):
assert not os.system(command)
- def del_tmp(self):
- """Make new testfiles/output dir"""
- self.run_cmd("rm -rf testfiles/output")
- os.mkdir("testfiles/output")
-
def run_rdiffdir(self, argstring):
"""Run rdiffdir with given arguments"""
self.run_cmd("rdiffdir " + argstring)
@@ -49,7 +38,6 @@
def run_cycle(self, dirname_list):
"""Run diff/patch cycle on directories in dirname_list"""
assert len(dirname_list) >= 2
- self.del_tmp()
seq_path = path.Path("testfiles/output/sequence")
new_path = path.Path(dirname_list[0])
=== renamed file 'testing/tests/test_restart.py' => 'testing/functional/test_restart.py'
--- testing/tests/test_restart.py 2014-04-17 21:49:37 +0000
+++ testing/functional/test_restart.py 2014-04-20 14:58:57 +0000
@@ -24,10 +24,10 @@
import subprocess
import unittest
-from helper import DuplicityTestCase
-
-
-class RestartTest(DuplicityTestCase):
+from . import FunctionalTestCase
+
+
+class RestartTest(FunctionalTestCase):
"""
Test checkpoint/restart using duplicity binary
"""
@@ -205,7 +205,6 @@
# 'restart' the backup
self.backup("full", source, options=["--volsize=5", "--name=backup1"])
# Confirm we actually resumed the previous backup
- print os.listdir("testfiles/output")
self.assertEqual(len(os.listdir("testfiles/output")), 4)
# Now make sure everything is byte-for-byte the same once restored
self.restore()
@@ -292,10 +291,10 @@
# Note that this class duplicates all the tests in RestartTest
class RestartTestWithoutEncryption(RestartTest):
- @classmethod
- def setUpClass(cls):
- super(RestartTestWithoutEncryption, cls).setUpClass()
- cls.class_args.extend(["--no-encryption"])
+
+ def setUp(self):
+ super(RestartTestWithoutEncryption, self).setUp()
+ self.class_args.extend(["--no-encryption"])
def test_no_write_double_snapshot(self):
"""
=== removed directory 'testing/helpers'
=== removed file 'testing/helpers/helper.py'
--- testing/helpers/helper.py 2014-04-17 19:34:23 +0000
+++ testing/helpers/helper.py 1970-01-01 00:00:00 +0000
@@ -1,191 +0,0 @@
-# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
-#
-# Copyright 2002 Ben Escoto <ben@xxxxxxxxxxx>
-# Copyright 2007 Kenneth Loafman <kenneth@xxxxxxxxxxx>
-#
-# This file is part of duplicity.
-#
-# Duplicity is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# Duplicity is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with duplicity; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-import os
-import pexpect
-import time
-import unittest
-
-from duplicity import backend
-from duplicity import globals
-from duplicity import log
-
-sign_key = '56538CCF'
-sign_passphrase = 'test'
-encrypt_key1 = 'B5FA894F'
-encrypt_key2 = '9B736B2A'
-
-def setup():
- """ setup for unit tests """
- # TODO: remove these lines
- log.setup()
- log.setverbosity(log.WARNING)
- globals.print_statistics = 0
- backend.import_backends()
-
- # Have all file references in tests relative to our testing dir
- _testing_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
- os.chdir(_testing_dir)
- # Make sure that PYTHONPATH is set right for subprocesses (setuptools
- # may futz with it)
- _top_dir = os.path.dirname(_testing_dir)
- os.environ['PYTHONPATH'] = _top_dir
-
-
-class CmdError(Exception):
- """Indicates an error running an external command"""
- def __init__(self, code):
- Exception.__init__(self, code)
- self.exit_status = code
-
-
-class DuplicityTestCase(unittest.TestCase):
- @classmethod
- def setUpClass(cls):
- cls.class_args = []
- cls.backend_url = "file://testfiles/output"
- cls.sign_key = sign_key
- cls.sign_passphrase = sign_passphrase
- cls.encrypt_key1 = encrypt_key1
- cls.encrypt_key2 = encrypt_key2
- setup()
-
- def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
- assert not os.system("rm -rf testfiles/output testfiles/largefiles "
- "testfiles/restore_out testfiles/cache")
- assert not os.system("mkdir testfiles/output testfiles/cache")
-
- backend_inst = backend.get_backend(self.backend_url)
- bl = backend_inst.list()
- if bl:
- backend_inst.delete(backend_inst.list())
- backend_inst.close()
-
- self.last_backup = None
- self.set_environ('PASSPHRASE', self.sign_passphrase)
- self.set_environ("SIGN_PASSPHRASE", self.sign_passphrase)
-
- def tearDown(self):
- self.set_environ("PASSPHRASE", None)
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
- def set_environ(self, varname, value):
- if value is not None:
- os.environ[varname] = value
- else:
- try:
- del os.environ[varname]
- except Exception:
- pass
-
- def run_duplicity(self, options=[], current_time=None, fail=None,
- passphrase_input=[]):
- """
- Run duplicity binary with given arguments and options
- """
- # We run under setsid and take input from /dev/null (below) because
- # this way we force a failure if duplicity tries to read from the
- # console unexpectedly (like for gpg password or such).
- cmd_list = ["setsid", "duplicity"]
- cmd_list.extend(options)
- cmd_list.extend(["-v0"])
- cmd_list.extend(["--no-print-statistics"])
- cmd_list.extend(["--allow-source-mismatch"])
- cmd_list.extend(["--archive-dir=testfiles/cache"])
- if current_time:
- cmd_list.extend(["--current-time", current_time])
- cmd_list.extend(self.class_args)
- if fail:
- cmd_list.extend(["--fail", str(fail)])
- cmdline = " ".join(map(lambda x: '"%s"' % x, cmd_list))
-
- if not passphrase_input:
- cmdline += " < /dev/null"
- child = pexpect.spawn('/bin/sh', ['-c', cmdline])
- for passphrase in passphrase_input:
- child.expect('passphrase.*:')
- child.sendline(passphrase)
- child.wait()
- return_val = child.exitstatus
-
- #print "Ran duplicity command: ", cmdline, "\n with return_val: ", child.exitstatus
- if fail:
- self.assertEqual(30, child.exitstatus)
- elif return_val:
- raise CmdError(child.exitstatus)
-
- def backup(self, type, input_dir, options=[], **kwargs):
- """Run duplicity backup to default directory"""
- options = [type, input_dir, self.backend_url, "--volsize", "1"] + options
- before_files = self.get_backend_files()
-
- # If a chain ends with time X and the next full chain begins at time X,
- # we may trigger an assert in collections.py. If needed, sleep to
- # avoid such problems
- if self.last_backup == int(time.time()):
- time.sleep(1)
-
- result = self.run_duplicity(options=options, **kwargs)
- self.last_backup = int(time.time())
-
- after_files = self.get_backend_files()
- return after_files - before_files
-
- def restore(self, file_to_restore=None, time=None, options=[], **kwargs):
- assert not os.system("rm -rf testfiles/restore_out")
- options = [self.backend_url, "testfiles/restore_out"] + options
- if file_to_restore:
- options.extend(['--file-to-restore', file_to_restore])
- if time:
- options.extend(['--restore-time', str(time)])
- self.run_duplicity(options=options, **kwargs)
-
- def verify(self, dirname, file_to_verify=None, time=None, options=[],
- **kwargs):
- options = ["verify", self.backend_url, dirname] + options
- if file_to_verify:
- options.extend(['--file-to-restore', file_to_verify])
- if time:
- options.extend(['--restore-time', str(time)])
- self.run_duplicity(options=options, **kwargs)
-
- def cleanup(self, options=[]):
- """
- Run duplicity cleanup to default directory
- """
- options = ["cleanup", self.backend_url, "--force"] + options
- self.run_duplicity(options=options)
-
- def get_backend_files(self):
- backend_inst = backend.get_backend(self.backend_url)
- bl = backend_inst.list()
- backend_inst.close()
- return set(bl)
-
- def make_largefiles(self, count=3, size=2):
- """
- Makes a number of large files in testfiles/largefiles that each are
- the specified number of megabytes.
- """
- assert not os.system("mkdir testfiles/largefiles")
- for n in range(count):
- assert not os.system("dd if=/dev/urandom of=testfiles/largefiles/file%d bs=1024 count=%d > /dev/null 2>&1" % (n + 1, size * 1024))
=== renamed file 'testing/rootfiles.tar.gz' => 'testing/manual/rootfiles.tar.gz'
=== modified file 'testing/manual/roottest.py'
--- testing/manual/roottest.py 2012-02-29 19:21:10 +0000
+++ testing/manual/roottest.py 2014-04-20 14:58:57 +0000
@@ -39,7 +39,7 @@
# make sure uid/gid match euid/egid
os.setuid(os.geteuid())
os.setgid(os.getegid())
- assert not os.system("tar xzf rootfiles.tar.gz > /dev/null 2>&1")
+ assert not os.system("tar xzf manual/rootfiles.tar.gz > /dev/null 2>&1")
def tearDown(self):
assert not os.system("rm -rf testfiles tempdir temp2.tar")
=== modified file 'testing/overrides/gettext.py'
--- testing/overrides/gettext.py 2014-02-05 02:57:01 +0000
+++ testing/overrides/gettext.py 2014-04-20 14:58:57 +0000
@@ -22,13 +22,8 @@
# always return a string with fancy unicode characters, which will notify us
# if we ever get a unicode->ascii translation by accident.
-def translation(*args, **kwargs):
- class Translation:
- ZWSP = u"" # ZERO WIDTH SPACE, basically an invisible space separator
- def install(self, **kwargs):
- import __builtin__
- __builtin__.__dict__['_'] = lambda x: x + self.ZWSP
- def ungettext(self, one, more, n):
- if n == 1: return one + self.ZWSP
- else: return more + self.ZWSP
- return Translation()
+def install(*args, **kwargs):
+ ZWSP = u"" # ZERO WIDTH SPACE, basically an invisible space separator
+ import __builtin__
+ __builtin__.__dict__['_'] = lambda x: x + ZWSP
+ __builtin__.__dict__['ngettext'] = lambda one, more, n: one + ZWSP if n == 1 else more + ZWSP
=== modified file 'testing/run-tests'
--- testing/run-tests 2014-04-16 20:45:09 +0000
+++ testing/run-tests 2014-04-20 14:58:57 +0000
@@ -20,54 +20,5 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-# Go to directory housing this script
-cd $(dirname $0)
-
-THISDIR=$(pwd)
-export PATH="$(dirname $THISDIR)/bin:$PATH"
-
-TOP_TESTS=$*
-if [ -z "$TOP_TESTS" ]; then
- TOP_TESTS="all"
-fi
-
-if [ "$TOP_TESTS" = "all" ]; then
- TOP_TESTS="tests" # don't include manual tests unless they were asked for
-fi
-
-# Expand arguments if directories
-TESTS=
-for t in $TOP_TESTS; do
- if [ -d "$t" ]; then
- TESTS="$TESTS $(ls $t/*.py)"
- else
- TESTS="$TESTS $t"
- fi
-done
-
-# run against all supported python versions
-for v in 2.6 2.7; do
- type python$v >& /dev/null
- if [ $? == 1 ]; then
- echo "python$v not found on system"
- continue
- fi
-
- echo "========== Compiling librsync for python$v =========="
- pushd ../duplicity
- python$v ./compilec.py
- popd
-
- for t in $TESTS; do
- echo "========== Running $t for python$v =========="
- pushd .
- if ! python$v -u $t -v 2>&1; then
- echo "Test failed"
- exit 1
- fi
- popd
- echo "========== Finished $t for python$v =========="
- echo
- echo
- done
-done
+cd $(dirname $(dirname $0))
+tox
=== modified file 'testing/run-tests-ve'
--- testing/run-tests-ve 2014-04-16 20:45:09 +0000
+++ testing/run-tests-ve 2014-04-20 14:58:57 +0000
@@ -20,57 +20,5 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-# Go to directory housing this script
-cd $(dirname $0)
-
-THISDIR=$(pwd)
-export PATH="$(dirname $THISDIR)/bin:$PATH"
-
-TOP_TESTS=$*
-if [ -z "$TOP_TESTS" ]; then
- TOP_TESTS="all"
-fi
-
-if [ "$TOP_TESTS" = "all" ]; then
- TOP_TESTS="tests" # don't include manual tests unless they were asked for
-fi
-
-# Expand arguments if directories
-TESTS=
-for t in $TOP_TESTS; do
- if [ -d "$t" ]; then
- TESTS="$TESTS $(ls $t/*.py)"
- else
- TESTS="$TESTS $t"
- fi
-done
-
-# run against all supported python versions
-for v in 2.6 2.7; do
- ve=~/virtual$v
- if [ $? == 1 ]; then
- echo "virtual$v not found on system"
- continue
- fi
- source $ve/bin/activate
-
- echo "========== Compiling librsync for virtual$v =========="
- pushd ../duplicity
- python ./compilec.py
- popd
-
- for t in $TESTS; do
- echo "========== Running $t for virtual$v =========="
- pushd .
- if ! python -u $t -v 2>&1; then
- echo "Test failed"
- exit 1
- fi
- popd
- echo "========== Finished $t for virtual$v =========="
- echo
- echo
- done
-
- deactivate
-done
+cd $(dirname $(dirname $0))
+tox
=== renamed file 'testing/tests/test_python3.py' => 'testing/test_code.py'
--- testing/tests/test_python3.py 2014-04-17 22:26:39 +0000
+++ testing/test_code.py 2014-04-20 14:58:57 +0000
@@ -18,43 +18,107 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import os
import subprocess
import unittest
-helper.setup()
-
-
-class Python3ReadinessTest(unittest.TestCase):
+from . import _top_dir, DuplicityTestCase
+
+
+class CodeTest(DuplicityTestCase):
+
+ def run_checker(self, cmd):
+ process = subprocess.Popen(cmd,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ output = process.communicate()[0]
+ self.assertEqual(0, process.returncode, output)
+ self.assertEqual("", output, output)
+
def test_2to3(self):
- _top_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- "..", "..")
-
# As we modernize the source code, we can remove more and more nofixes
- process = subprocess.Popen(["2to3",
- "--nofix=dict",
- "--nofix=filter",
- "--nofix=map",
- "--nofix=next",
- "--nofix=print",
- "--nofix=types",
- "--nofix=unicode",
- "--nofix=xrange",
+ self.run_checker(["2to3",
+ "--nofix=dict",
+ "--nofix=filter",
+ "--nofix=map",
+ "--nofix=next",
+ "--nofix=print",
+ "--nofix=types",
+ "--nofix=unicode",
+ "--nofix=xrange",
# The following fixes we don't want to remove, since they are false
# positives, things we don't care about, or real incompatibilities
# but which 2to3 can fix for us better automatically.
- "--nofix=callable",
- "--nofix=future",
- "--nofix=imports",
- "--nofix=raw_input",
- "--nofix=urllib",
- _top_dir],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
- output = process.communicate()[0]
- self.assertEqual(0, process.returncode)
- self.assertEqual("", output, output)
+ "--nofix=callable",
+ "--nofix=future",
+ "--nofix=imports",
+ "--nofix=raw_input",
+ "--nofix=urllib",
+ _top_dir])
+
+ def test_pylint(self):
+ self.run_checker(["pylint",
+ "-E",
+ "--msg-template={msg_id}: {line}: {msg}",
+ "--disable=E0203", # Access to member before its definition line
+ "--disable=E0602", # Undefined variable
+ "--disable=E0611", # No name in module
+ "--disable=E1101", # Has no member
+ "--disable=E1103", # Maybe has no member
+ "--ignore=_librsync.so",
+ os.path.join(_top_dir, 'duplicity'),
+ os.path.join(_top_dir, 'bin/duplicity'),
+ os.path.join(_top_dir, 'bin/rdiffdir')])
+
+ def test_pep8(self):
+ # All these ignores are just because when this test was added, I didn't
+ # want to fix all of the code. Over time we can remove some of these
+ # and clean up the code. But for now, let's at least get *some* pep8
+ # coverage.
+ ignores = ["E111",
+ "E121",
+ "E122",
+ "E124",
+ "E125",
+ "E126",
+ "E127",
+ "E128",
+ "E201",
+ "E202",
+ "E203",
+ "E211",
+ "E221",
+ "E222",
+ "E225",
+ "E226",
+ "E228",
+ "E231",
+ "E241",
+ "E251",
+ "E261",
+ "E262",
+ "E271",
+ "E272",
+ "E301",
+ "E302",
+ "E303",
+ "E401",
+ "E501",
+ "E502",
+ "E701",
+ "E702",
+ "E703",
+ "E711",
+ "E721",
+ "W291",
+ "W292",
+ "W293",
+ "W391"]
+ self.run_checker(["pep8",
+ "--ignore=" + ','.join(ignores),
+ os.path.join(_top_dir, 'duplicity'),
+ os.path.join(_top_dir, 'bin/duplicity'),
+ os.path.join(_top_dir, 'bin/rdiffdir')])
if __name__ == "__main__":
=== removed directory 'testing/tests'
=== removed file 'testing/tests/test_misc.py'
--- testing/tests/test_misc.py 2014-04-16 02:43:43 +0000
+++ testing/tests/test_misc.py 1970-01-01 00:00:00 +0000
@@ -1,91 +0,0 @@
-# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
-#
-# Copyright 2002 Ben Escoto <ben@xxxxxxxxxxx>
-# Copyright 2007 Kenneth Loafman <kenneth@xxxxxxxxxxx>
-#
-# This file is part of duplicity.
-#
-# Duplicity is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# Duplicity is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with duplicity; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-import helper
-import sys, os, unittest, cStringIO
-
-from duplicity import misc
-
-helper.setup()
-
-class MiscTest(unittest.TestCase):
- """Test functions/classes in misc.py"""
- def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
- def deltmp(self):
- assert not os.system("rm -rf testfiles/output")
- os.mkdir("testfiles/output")
-
- def test_file_volume_writer(self):
- """Test FileVolumeWriter class"""
- self.deltmp()
- s = "hello" * 10000
- assert len(s) == 50000
- infp = cStringIO.StringIO(s)
- fvw = misc.FileVolumeWriter(infp, "testfiles/output/volume")
- fvw.volume_size = 20000
- fvw.blocksize = 5000
-
- l = []
- for filename in fvw: l.append(filename)
- assert l == ['testfiles/output/volume.1',
- 'testfiles/output/volume.2',
- 'testfiles/output/volume.3'], l
-
- s2 = ""
- for filename in l:
- infp2 = open(filename, "rb")
- s2 += infp2.read()
- assert not infp2.close()
-
- assert s2 == s
-
- def test_file_volume_writer2(self):
- """Test again but one volume this time"""
- self.deltmp()
- fvw = misc.FileVolumeWriter(cStringIO.StringIO("hello, world!"),
- "testfiles/output/one_vol")
- assert fvw.next() == "testfiles/output/one_vol"
- self.assertRaises(StopIteration, fvw.next)
-
- def test_file_volume_writer3(self):
- """Test case when end of file falls exactly on volume boundary"""
- self.deltmp()
- s = "hello" * 10000
- assert len(s) == 50000
- infp = cStringIO.StringIO(s)
- fvw = misc.FileVolumeWriter(infp, "testfiles/output/volume")
- fvw.volume_size = 25000
- fvw.blocksize = 5000
-
- l = []
- for filename in fvw: l.append(filename)
- assert l == ['testfiles/output/volume.1',
- 'testfiles/output/volume.2']
-
-
-
-if __name__ == "__main__":
- unittest.main()
=== removed file 'testing/tests/test_unicode.py'
--- testing/tests/test_unicode.py 2014-04-16 20:45:09 +0000
+++ testing/tests/test_unicode.py 1970-01-01 00:00:00 +0000
@@ -1,39 +0,0 @@
-# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
-#
-# Copyright 2012 Canonical Ltd
-#
-# This file is part of duplicity.
-#
-# Duplicity is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 2 of the License, or (at your
-# option) any later version.
-#
-# Duplicity is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with duplicity; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-import sys
-import unittest
-from mock import patch
-
-
-class UTF8Test(unittest.TestCase):
-
- def setUp(self):
- if 'duplicity' in sys.modules:
- del(sys.modules["duplicity"])
-
- @patch('gettext.install')
- def test_module_install(self, gettext_mock):
- """Make sure we convert translations to unicode"""
- import duplicity
- gettext_mock.assert_called_once_with('duplicity', unicode=True, names=['ngettext'])
-
-if __name__ == "__main__":
- unittest.main()
=== added directory 'testing/unit'
=== added file 'testing/unit/__init__.py'
--- testing/unit/__init__.py 1970-01-01 00:00:00 +0000
+++ testing/unit/__init__.py 2014-04-20 14:58:57 +0000
@@ -0,0 +1,25 @@
+# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
+#
+# Copyright 2012 Canonical Ltd
+#
+# This file is part of duplicity.
+#
+# Duplicity is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# Duplicity is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with duplicity; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+from .. import DuplicityTestCase
+
+
+class UnitTestCase(DuplicityTestCase):
+ pass
=== renamed file 'testing/tests/test_parsedurl.py' => 'testing/unit/test_backend.py'
--- testing/tests/test_parsedurl.py 2014-04-16 20:45:09 +0000
+++ testing/unit/test_backend.py 2014-04-20 14:58:57 +0000
@@ -19,16 +19,15 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
-import sys, unittest
+import unittest
import duplicity.backend
import duplicity.backends #@UnusedImport
from duplicity.errors import * #@UnusedWildImport
-
-helper.setup()
-
-class ParsedUrlTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class ParsedUrlTest(UnitTestCase):
"""Test the ParsedUrl class"""
def test_basic(self):
"""Test various url strings"""
=== renamed file 'testing/tests/test_collections.py' => 'testing/unit/test_collections.py'
--- testing/tests/test_collections.py 2014-04-17 21:49:37 +0000
+++ testing/unit/test_collections.py 2014-04-20 14:58:57 +0000
@@ -19,17 +19,15 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import os, sys, random, unittest
from duplicity import collections
from duplicity import backend
+from duplicity import globals
from duplicity import path
from duplicity import gpg
-from duplicity import globals
from duplicity import dup_time
-
-helper.setup()
+from . import UnitTestCase
filename_list1 = ["duplicity-full.2002-08-17T16:17:01-07:00.manifest.gpg",
"duplicity-full.2002-08-17T16:17:01-07:00.vol1.difftar.gpg",
@@ -71,15 +69,16 @@
"Extra stuff to be ignored"]
-class CollectionTest(unittest.TestCase):
+class CollectionTest(UnitTestCase):
"""Test collections"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
- assert not os.system("mkdir testfiles/output")
+ super(CollectionTest, self).setUp()
+
+ self.unpack_testfiles()
col_test_dir = path.Path("testfiles/collectionstest")
archive_dir = col_test_dir.append("archive_dir")
- globals.archive_dir = archive_dir
+ self.set_global('archive_dir', archive_dir)
self.archive_dir_backend = backend.get_backend("file://testfiles/collectionstest"
"/archive_dir")
@@ -88,17 +87,9 @@
self.output_dir = path.Path("testfiles/output") # used as a temp directory
self.output_dir_backend = backend.get_backend("file://testfiles/output")
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
- def del_tmp(self):
- """Reset the testfiles/output directory"""
- self.output_dir.deltree()
- self.output_dir.mkdir()
-
def set_gpg_profile(self):
"""Set gpg profile to standard "foobar" sym"""
- globals.gpg_profile = gpg.GPGProfile(passphrase = "foobar")
+ self.set_global('gpg_profile', gpg.GPGProfile(passphrase = "foobar"))
def test_backup_chains(self):
"""Test basic backup chain construction"""
@@ -193,7 +184,6 @@
def get_filelist2_cs(self):
"""Return set CollectionsStatus object from filelist 2"""
# Set up testfiles/output with files from filename_list2
- self.del_tmp()
for filename in filename_list2:
p = self.output_dir.append(filename)
p.touch()
=== renamed file 'testing/tests/test_diffdir.py' => 'testing/unit/test_diffdir.py'
--- testing/tests/test_diffdir.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_diffdir.py 2014-04-20 14:58:57 +0000
@@ -19,7 +19,6 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import os, sys, unittest
from duplicity.path import * #@UnusedWildImport
@@ -27,16 +26,14 @@
from duplicity import selection
from duplicity import util
from duplicity import tarfile #@Reimport
-
-helper.setup()
-
-class DDTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class DDTest(UnitTestCase):
"""Test functions in diffdir.py"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
+ super(DDTest, self).setUp()
+ self.unpack_testfiles()
def copyfileobj(self, infp, outfp):
"""Copy in fileobj to out, closing afterwards"""
@@ -48,14 +45,8 @@
assert not infp.close()
assert not outfp.close()
- def deltmp(self):
- """Delete temporary directories"""
- assert not os.system("rm -rf testfiles/output")
- os.mkdir("testfiles/output")
-
def testsig(self):
"""Test producing tar signature of various file types"""
- self.deltmp()
select = selection.Select(Path("testfiles/various_file_types"))
select.set_iter()
sigtar = diffdir.SigTarBlockIter(select)
@@ -68,7 +59,6 @@
def empty_diff_schema(self, dirname):
"""Given directory name, make sure can tell when nothing changes"""
- self.deltmp()
select = selection.Select(Path(dirname))
select.set_iter()
sigtar = diffdir.SigTarBlockIter(select)
@@ -91,9 +81,7 @@
def test_empty_diff(self):
"""Test producing a diff against same sig; should be len 0"""
self.empty_diff_schema("testfiles/various_file_types")
- return
- self.deltmp()
select = selection.Select(Path("testfiles/various_file_types"))
select.set_iter()
sigtar = diffdir.SigTarBlockIter(select)
@@ -114,7 +102,6 @@
def test_diff(self):
"""Test making a diff"""
- self.deltmp()
sel1 = selection.Select(Path("testfiles/dir1"))
diffdir.write_block_iter(diffdir.SigTarBlockIter(sel1.set_iter()),
"testfiles/output/dir1.sigtar")
@@ -141,7 +128,6 @@
def test_diff2(self):
"""Another diff test - this one involves multivol support"""
- self.deltmp()
sel1 = selection.Select(Path("testfiles/dir2"))
diffdir.write_block_iter(diffdir.SigTarBlockIter(sel1.set_iter()),
"testfiles/output/dir2.sigtar")
@@ -175,7 +161,6 @@
those produced by DirDelta_WriteSig and other methods.
"""
- self.deltmp()
deltadir1 = Path("testfiles/output/dir.deltatar1") #@UnusedVariable
deltadir2 = Path("testfiles/output/dir.deltatar2") #@UnusedVariable
cur_full_sigs = Path("testfiles/output/fullsig.dir1")
=== renamed file 'testing/tests/test_temp.py' => 'testing/unit/test_dup_temp.py'
--- testing/tests/test_temp.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_dup_temp.py 2014-04-20 14:58:57 +0000
@@ -19,28 +19,16 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
-import sys, os, unittest, gzip
+import gzip
+import unittest
from duplicity import dup_temp
from duplicity import file_naming
-
-helper.setup()
-
-prefix = "testfiles/output"
-
-class TempTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class TempTest(UnitTestCase):
"""Test various temp files methods"""
- def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
- def del_tmp(self):
- """Delete testfiles/output and recreate"""
- assert not os.system("rm -rf " + prefix)
- assert not os.system("mkdir " + prefix)
def test_temppath(self):
"""Allocate new temppath, try open_with_delete"""
=== renamed file 'testing/tests/test_time.py' => 'testing/unit/test_dup_time.py'
--- testing/tests/test_time.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_dup_time.py 2014-04-20 14:58:57 +0000
@@ -19,13 +19,10 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import sys, unittest, time, types
-from copy import copy
-from duplicity import globals
from duplicity import dup_time
+from . import UnitTestCase
-helper.setup()
class TimeTest:
def testConversion(self):
@@ -41,12 +38,8 @@
def testConversion_separator(self):
"""Same as testConversion, but change time Separator"""
- prev_sep = copy(globals.time_separator)
- try:
- globals.time_separator = "_"
- self.testConversion()
- finally:
- globals.time_separator = prev_sep
+ self.set_global('time_separator', "_")
+ self.testConversion()
def testCmp(self):
"""Test time comparisons"""
@@ -64,19 +57,15 @@
def testCmp_separator(self):
"""Like testCmp but with new separator"""
- prev_sep = copy(globals.time_separator)
- try:
- globals.time_separator = "_"
- cmp = dup_time.cmp
- assert cmp(1,2) == -1
- assert cmp(2,2) == 0
- assert cmp(5,1) == 1
- assert cmp("2001-09-01T21_49_04Z", "2001-08-01T21_49_04Z") == 1
- assert cmp("2001-09-01T04_49_04+03_23", "2001-09-01T21_49_04Z") == -1
- assert cmp("2001-09-01T12_00_00Z", "2001-09-01T04_00_00-08_00") == 0
- assert cmp("2001-09-01T12_00_00-08_00", "2001-09-01T12_00_00-07_00") == 1
- finally:
- globals.time_separator = prev_sep
+ self.set_global('time_separator', "_")
+ cmp = dup_time.cmp
+ assert cmp(1,2) == -1
+ assert cmp(2,2) == 0
+ assert cmp(5,1) == 1
+ assert cmp("2001-09-01T21_49_04Z", "2001-08-01T21_49_04Z") == 1
+ assert cmp("2001-09-01T04_49_04+03_23", "2001-09-01T21_49_04Z") == -1
+ assert cmp("2001-09-01T12_00_00Z", "2001-09-01T04_00_00-08_00") == 0
+ assert cmp("2001-09-01T12_00_00-08_00", "2001-09-01T12_00_00-07_00") == 1
def testStringtotime(self):
"""Test converting string to time"""
@@ -144,15 +133,19 @@
t = int(time.time())
assert dup_time.stringtotime(dup_time.timetostring(t)) == t
-class TimeTest1(TimeTest, unittest.TestCase):
-
- def setUp(self):
- globals.old_filenames = False
-
-class TimeTest2(TimeTest, unittest.TestCase):
-
- def setUp(self):
- globals.old_filenames = True
+
+class TimeTest1(TimeTest, UnitTestCase):
+
+ def setUp(self):
+ super(TimeTest1, self).setUp()
+ self.set_global('old_filenames', False)
+
+
+class TimeTest2(TimeTest, UnitTestCase):
+
+ def setUp(self):
+ super(TimeTest2, self).setUp()
+ self.set_global('old_filenames', True)
if __name__ == '__main__':
unittest.main()
=== renamed file 'testing/tests/test_filenaming.py' => 'testing/unit/test_file_naming.py'
--- testing/tests/test_filenaming.py 2014-04-17 21:49:37 +0000
+++ testing/unit/test_file_naming.py 2014-04-20 14:58:57 +0000
@@ -19,17 +19,16 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
-import sys, unittest
+import unittest
from duplicity import dup_time
from duplicity import file_naming
from duplicity import log
from duplicity import globals
-
-helper.setup()
-
-class Test36(unittest.TestCase):
+from . import UnitTestCase
+
+
+class Test36(UnitTestCase):
def test_base36(self):
"""Test conversion to/from base 36"""
numlist = [0, 1, 10, 1313, 34233, 872338, 2342889,
@@ -124,23 +123,28 @@
assert pr.time == 1036954144, repr(pr.time)
-class FileNamingLong(unittest.TestCase, FileNamingBase):
+class FileNamingLong(UnitTestCase, FileNamingBase):
"""Test long filename parsing and generation"""
def setUp(self):
- globals.short_filenames = 0
-
-class FileNamingShort(unittest.TestCase, FileNamingBase):
+ super(FileNamingLong, self).setUp()
+ self.set_global('short_filenames', 0)
+
+
+class FileNamingShort(UnitTestCase, FileNamingBase):
"""Test short filename parsing and generation"""
def setUp(self):
- globals.short_filenames = 1
+ super(FileNamingShort, self).setUp()
+ self.set_global('short_filenames', 1)
+
-class FileNamingPrefixes(unittest.TestCase, FileNamingBase):
+class FileNamingPrefixes(UnitTestCase, FileNamingBase):
"""Test filename parsing and generation with prefixes"""
def setUp(self):
- globals.file_prefix = "global-"
- globals.file_prefix_manifest = "mani-"
- globals.file_prefix_signature = "sign-"
- globals.file_prefix_archive = "arch-"
+ super(FileNamingPrefixes, self).setUp()
+ self.set_global('file_prefix', "global-")
+ self.set_global('file_prefix_manifest', "mani-")
+ self.set_global('file_prefix_signature', "sign-")
+ self.set_global('file_prefix_archive', "arch-")
if __name__ == "__main__":
=== renamed file 'testing/tests/test_gpg.py' => 'testing/unit/test_gpg.py'
--- testing/tests/test_gpg.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_gpg.py 2014-04-20 14:58:57 +0000
@@ -19,31 +19,22 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import sys, os, unittest, random
from duplicity import gpg
from duplicity import path
-
-helper.setup()
-
-class GPGTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class GPGTest(UnitTestCase):
"""Test GPGFile"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
+ super(GPGTest, self).setUp()
+ self.unpack_testfiles()
self.default_profile = gpg.GPGProfile(passphrase = "foobar")
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
- def deltmp(self):
- """Delete testfiles/output and recreate"""
- assert not os.system("rm -rf testfiles/output")
- assert not os.system("mkdir testfiles/output")
-
def gpg_cycle(self, s, profile = None):
"""Test encryption/decryption cycle on string s"""
- self.deltmp()
epath = path.Path("testfiles/output/encrypted_file")
if not profile:
profile = self.default_profile
@@ -77,34 +68,33 @@
def test_gpg_asym(self):
"""Test GPG asymmetric encryption"""
- profile = gpg.GPGProfile(passphrase = helper.sign_passphrase,
- recipients = [helper.encrypt_key1,
- helper.encrypt_key2])
+ profile = gpg.GPGProfile(passphrase = self.sign_passphrase,
+ recipients = [self.encrypt_key1,
+ self.encrypt_key2])
self.gpg_cycle("aoensutha aonetuh saoe", profile)
- profile2 = gpg.GPGProfile(passphrase = helper.sign_passphrase,
- recipients = [helper.encrypt_key1])
+ profile2 = gpg.GPGProfile(passphrase = self.sign_passphrase,
+ recipients = [self.encrypt_key1])
self.gpg_cycle("aoeu" * 10000, profile2)
def test_gpg_hidden_asym(self):
"""Test GPG asymmetric encryption with hidden key id"""
- profile = gpg.GPGProfile(passphrase = helper.sign_passphrase,
- hidden_recipients = [helper.encrypt_key1,
- helper.encrypt_key2])
+ profile = gpg.GPGProfile(passphrase = self.sign_passphrase,
+ hidden_recipients = [self.encrypt_key1,
+ self.encrypt_key2])
self.gpg_cycle("aoensutha aonetuh saoe", profile)
- profile2 = gpg.GPGProfile(passphrase = helper.sign_passphrase,
- hidden_recipients = [helper.encrypt_key1])
+ profile2 = gpg.GPGProfile(passphrase = self.sign_passphrase,
+ hidden_recipients = [self.encrypt_key1])
self.gpg_cycle("aoeu" * 10000, profile2)
def test_gpg_signing(self):
"""Test to make sure GPG reports the proper signature key"""
- self.deltmp()
plaintext = "hello" * 50000
- signing_profile = gpg.GPGProfile(passphrase = helper.sign_passphrase,
- sign_key = helper.sign_key,
- recipients = [helper.encrypt_key1])
+ signing_profile = gpg.GPGProfile(passphrase = self.sign_passphrase,
+ sign_key = self.sign_key,
+ recipients = [self.encrypt_key1])
epath = path.Path("testfiles/output/encrypted_file")
encrypted_signed_file = gpg.GPGFile(1, epath, signing_profile)
@@ -115,16 +105,15 @@
assert decrypted_file.read() == plaintext
decrypted_file.close()
sig = decrypted_file.get_signature()
- assert sig == helper.sign_key, sig
+ assert sig == self.sign_key, sig
def test_gpg_signing_and_hidden_encryption(self):
"""Test to make sure GPG reports the proper signature key even with hidden encryption key id"""
- self.deltmp()
plaintext = "hello" * 50000
- signing_profile = gpg.GPGProfile(passphrase = helper.sign_passphrase,
- sign_key = helper.sign_key,
- hidden_recipients = [helper.encrypt_key1])
+ signing_profile = gpg.GPGProfile(passphrase = self.sign_passphrase,
+ sign_key = self.sign_key,
+ hidden_recipients = [self.encrypt_key1])
epath = path.Path("testfiles/output/encrypted_file")
encrypted_signed_file = gpg.GPGFile(1, epath, signing_profile)
@@ -135,11 +124,10 @@
assert decrypted_file.read() == plaintext
decrypted_file.close()
sig = decrypted_file.get_signature()
- assert sig == helper.sign_key, sig
+ assert sig == self.sign_key, sig
def test_GPGWriteFile(self):
"""Test GPGWriteFile"""
- self.deltmp()
size = 400 * 1000
gwfh = GPGWriteFile_Helper()
profile = gpg.GPGProfile(passphrase = "foobar")
@@ -155,7 +143,6 @@
def test_GzipWriteFile(self):
"""Test GzipWriteFile"""
- self.deltmp()
size = 400 * 1000
gwfh = GPGWriteFile_Helper()
for i in range(10): #@UnusedVariable
@@ -171,6 +158,7 @@
class GPGWriteHelper2:
def __init__(self, data): self.data = data
+
class GPGWriteFile_Helper:
"""Used in test_GPGWriteFile above"""
def __init__(self):
@@ -203,13 +191,11 @@
return "e" * random.randrange(0, 15000)
-class SHATest(unittest.TestCase):
+class SHATest(UnitTestCase):
"""Test making sha signatures"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
+ super(SHATest, self).setUp()
+ self.unpack_testfiles()
def test_sha(self):
hash = gpg.get_hash("SHA1", path.Path("testfiles/various_file_types/regular_file"))
=== renamed file 'testing/tests/test_GnuPGInterface.py' => 'testing/unit/test_gpginterface.py'
=== renamed file 'testing/tests/test_lazy.py' => 'testing/unit/test_lazy.py'
--- testing/tests/test_lazy.py 2014-04-17 21:15:36 +0000
+++ testing/unit/test_lazy.py 2014-04-20 14:58:57 +0000
@@ -19,22 +19,21 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import unittest, pickle, sys
from functools import reduce
from duplicity.lazy import * #@UnusedWildImport
-
-helper.setup()
-
-class Iterators(unittest.TestCase):
+from . import UnitTestCase
+
+
+class Iterators(UnitTestCase):
one_to_100 = lambda s: iter(range(1, 101))
evens = lambda s: iter(range(2, 101, 2))
odds = lambda s: iter(range(1, 100, 2))
empty = lambda s: iter([])
def __init__(self, *args):
- unittest.TestCase.__init__(self, *args)
+ super(Iterators, self).__init__(*args)
self.falseerror = self.falseerror_maker()
self.trueerror = self.trueerror_maker()
self.emptygen = self.emptygen_maker()
@@ -275,8 +274,10 @@
#print "Adding branch ", subinstance.total
self.total += subinstance.total
-class TreeReducerTest(unittest.TestCase):
+class TreeReducerTest(UnitTestCase):
def setUp(self):
+ super(TreeReducerTest, self).setUp()
+
self.i1 = [(), (1,), (2,), (3,)]
self.i2 = [(0,), (0,1), (0,1,0), (0,1,1), (0,2), (0,2,1), (0,3)]
=== renamed file 'testing/tests/test_manifest.py' => 'testing/unit/test_manifest.py'
--- testing/tests/test_manifest.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_manifest.py 2014-04-20 14:58:57 +0000
@@ -19,16 +19,16 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
-import sys, unittest, types
+import types
+import unittest
from duplicity import manifest
-from duplicity import globals
from duplicity import path
-
-helper.setup()
-
-class VolumeInfoTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+
+class VolumeInfoTest(UnitTestCase):
"""Test VolumeInfo"""
def test_basic(self):
"""Basic VolumeInfoTest"""
@@ -75,7 +75,7 @@
assert not vi3.contains(("3",), recursive = 0)
-class ManifestTest(unittest.TestCase):
+class ManifestTest(UnitTestCase):
"""Test Manifest class"""
def test_basic(self):
vi1 = manifest.VolumeInfo()
@@ -87,7 +87,7 @@
m = manifest.Manifest()
for vi in [vi1, vi2, vi3]: m.add_volume_info(vi)
- globals.local_path = path.Path("Foobar")
+ self.set_global('local_path', path.Path("Foobar"))
m.set_dirinfo()
s = m.to_string()
=== renamed file 'testing/tests/test_patchdir.py' => 'testing/unit/test_patchdir.py'
--- testing/tests/test_patchdir.py 2014-04-17 21:49:37 +0000
+++ testing/unit/test_patchdir.py 2014-04-20 14:58:57 +0000
@@ -19,7 +19,6 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import sys, cStringIO, unittest
from duplicity import diffdir
@@ -29,16 +28,14 @@
from duplicity import tarfile #@UnusedImport
from duplicity import librsync #@UnusedImport
from duplicity.path import * #@UnusedWildImport
-
-helper.setup()
-
-class PatchingTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class PatchingTest(UnitTestCase):
"""Test patching"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
+ super(PatchingTest, self).setUp()
+ self.unpack_testfiles()
def copyfileobj(self, infp, outfp):
"""Copy in fileobj to out, closing afterwards"""
@@ -50,11 +47,6 @@
assert not infp.close()
assert not outfp.close()
- def deltmp(self):
- """Delete temporary directories"""
- assert not os.system("rm -rf testfiles/output")
- os.mkdir("testfiles/output")
-
def test_total(self):
"""Test cycle on dirx"""
self.total_sequence(['testfiles/dir1',
@@ -68,7 +60,6 @@
def total_sequence(self, filelist):
"""Test signatures, diffing, and patching on directory list"""
assert len(filelist) >= 2
- self.deltmp()
sig = Path("testfiles/output/sig.tar")
diff = Path("testfiles/output/diff.tar")
seq_path = Path("testfiles/output/sequence")
@@ -107,7 +98,6 @@
def test_doubledot_hole(self):
"""Test for the .. bug that lets tar overwrite parent dir"""
- self.deltmp()
def make_bad_tar(filename):
"""Write attack tarfile to filename"""
@@ -124,7 +114,6 @@
tf.close()
- self.deltmp()
make_bad_tar("testfiles/output/bad.tar")
os.mkdir("testfiles/output/temp")
@@ -139,12 +128,10 @@
def __init__(self, index):
self.index = index
-class CollateItersTest(unittest.TestCase):
+class CollateItersTest(UnitTestCase):
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
+ super(CollateItersTest, self).setUp()
+ self.unpack_testfiles()
def test_collate(self):
"""Test collate_iters function"""
@@ -193,15 +180,13 @@
assert c == 3
-class TestInnerFuncs(unittest.TestCase):
+class TestInnerFuncs(UnitTestCase):
"""Test some other functions involved in patching"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
+ super(TestInnerFuncs, self).setUp()
+ self.unpack_testfiles()
self.check_output()
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
def check_output(self):
"""Make sure testfiles/output exists"""
out = Path("testfiles/output")
=== renamed file 'testing/tests/test_path.py' => 'testing/unit/test_path.py'
--- testing/tests/test_path.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_path.py 2014-04-20 14:58:57 +0000
@@ -19,25 +19,21 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import sys, unittest
from duplicity import log #@UnusedImport
from duplicity.path import * #@UnusedWildImport
-
-helper.setup()
-
-class PathTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class PathTest(UnitTestCase):
"""Test basic path functions"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
+ super(PathTest, self).setUp()
+ self.unpack_testfiles()
def test_deltree(self):
"""Test deleting a tree"""
- assert not os.system("rm -rf testfiles/output")
assert not os.system("cp -pR testfiles/deltree testfiles/output")
p = Path("testfiles/output")
assert p.isdir()
@@ -48,7 +44,6 @@
# will never be equal (they don't implement __cmp__ or __eq__)
#def test_compare(self):
# """Test directory comparisons"""
- # assert not os.system("rm -rf testfiles/output")
# assert not os.system("cp -pR testfiles/dir1 testfiles/output")
# assert Path("testfiles/dir1").compare_recursive(Path("testfiles/output"), 1)
# assert not Path("testfiles/dir1").compare_recursive(Path("testfiles/dir2"), 1)
=== renamed file 'testing/tests/test_selection.py' => 'testing/unit/test_selection.py'
--- testing/tests/test_selection.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_selection.py 2014-04-20 14:58:57 +0000
@@ -20,24 +20,22 @@
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import types
-import helper
import StringIO, unittest, sys
from duplicity.selection import * #@UnusedWildImport
from duplicity.lazy import * #@UnusedWildImport
-
-helper.setup()
-
-class MatchingTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+
+class MatchingTest(UnitTestCase):
"""Test matching of file names against various selection functions"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
+ super(MatchingTest, self).setUp()
+ self.unpack_testfiles()
self.root = Path("testfiles/select")
self.Select = Select(self.root)
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
def makeext(self, path):
return self.root.new_index(tuple(path.split("/")))
@@ -122,7 +120,7 @@
def testFilelistIncludeNullSep(self):
"""Test included filelist but with null_separator set"""
fp = StringIO.StringIO("""\0testfiles/select/1/2\0testfiles/select/1\0testfiles/select/1/2/3\0testfiles/select/3/3/2\0testfiles/select/hello\nthere\0""")
- globals.null_separator = 1
+ self.set_global('null_separator', 1)
sf = self.Select.filelist_get_sf(fp, 1, "test")
assert sf(self.root) == 1
assert sf(self.makeext("1")) == 1
@@ -133,7 +131,6 @@
assert sf(self.makeext("3/3")) == 1
assert sf(self.makeext("3/3/3")) == None
assert sf(self.makeext("hello\nthere")) == 1
- globals.null_separator = 0
def testFilelistExclude(self):
"""Test included filelist"""
@@ -271,15 +268,13 @@
assert sf(Path("/proc")) == sfval, \
"Assumption: /proc is on a different filesystem"
-class ParseArgsTest(unittest.TestCase):
+class ParseArgsTest(UnitTestCase):
"""Test argument parsing"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
-
- root = None
+ super(ParseArgsTest, self).setUp()
+ self.unpack_testfiles()
+ self.root = None
+
def ParseTest(self, tuplelist, indicies, filelists = []):
"""No error if running select on tuple goes over indicies"""
if not self.root:
=== renamed file 'testing/tests/test_statistics.py' => 'testing/unit/test_statistics.py'
--- testing/tests/test_statistics.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_statistics.py 2014-04-20 14:58:57 +0000
@@ -19,21 +19,18 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import sys, unittest
from duplicity.statistics import * #@UnusedWildImport
from duplicity import path
-
-helper.setup()
-
-class StatsObjTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class StatsObjTest(UnitTestCase):
"""Test StatsObj class"""
def setUp(self):
- assert not os.system("tar xzf testfiles.tar.gz > /dev/null 2>&1")
-
- def tearDown(self):
- assert not os.system("rm -rf testfiles tempdir temp2.tar")
+ super(StatsObjTest, self).setUp()
+ self.unpack_testfiles()
def set_obj(self, s):
"""Set values of s's statistics"""
=== renamed file 'testing/tests/test_tarfile.py' => 'testing/unit/test_tarfile.py'
--- testing/tests/test_tarfile.py 2014-04-16 20:45:09 +0000
+++ testing/unit/test_tarfile.py 2014-04-20 14:58:57 +0000
@@ -18,15 +18,13 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
import unittest
from duplicity import cached_ops
from duplicity import tarfile
-
-helper.setup()
-
-
-class TarfileTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class TarfileTest(UnitTestCase):
def test_cached_ops(self):
self.assertTrue(tarfile.grp is cached_ops)
self.assertTrue(tarfile.pwd is cached_ops)
=== renamed file 'testing/tests/test_tempdir.py' => 'testing/unit/test_tempdir.py'
--- testing/tests/test_tempdir.py 2014-04-16 02:43:43 +0000
+++ testing/unit/test_tempdir.py 2014-04-20 14:58:57 +0000
@@ -19,14 +19,14 @@
# along with duplicity; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-import helper
-import sys, os, unittest
+import os
+import unittest
from duplicity import tempdir
-
-helper.setup()
-
-class TempDirTest(unittest.TestCase):
+from . import UnitTestCase
+
+
+class TempDirTest(UnitTestCase):
def test_all(self):
td = tempdir.default()
@@ -48,4 +48,3 @@
if __name__ == "__main__":
unittest.main()
-
=== modified file 'tox.ini'
--- tox.ini 2014-04-17 19:34:23 +0000
+++ tox.ini 2014-04-20 14:58:57 +0000
@@ -4,6 +4,5 @@
[testenv]
deps=lockfile
mock
- nose
pexpect
-commands=nosetests
+commands={envpython} ./setup.py test
Follow ups