|
@@ -318,8 +318,6 @@ class ArchiverTestCaseBase(BaseTestCase):
|
|
|
"""Create a minimal test case including all supported file types
|
|
|
"""
|
|
|
# File
|
|
|
- self.create_regular_file('empty', size=0)
|
|
|
- os.utime('input/empty', (MAX_S, MAX_S))
|
|
|
self.create_regular_file('file1', size=1024 * 80)
|
|
|
self.create_regular_file('flagfile', size=1024)
|
|
|
# Directory
|
|
@@ -370,6 +368,8 @@ class ArchiverTestCaseBase(BaseTestCase):
|
|
|
if e.errno not in (errno.EINVAL, errno.ENOSYS):
|
|
|
raise
|
|
|
have_root = False
|
|
|
+ time.sleep(1) # "empty" must have newer timestamp than other files
|
|
|
+ self.create_regular_file('empty', size=0)
|
|
|
return have_root
|
|
|
|
|
|
|
|
@@ -1591,9 +1591,8 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|
|
"""test that various file status show expected results
|
|
|
|
|
|
clearly incomplete: only tests for the weird "unchanged" status for now"""
|
|
|
- now = time.time()
|
|
|
self.create_regular_file('file1', size=1024 * 80)
|
|
|
- os.utime('input/file1', (now - 5, now - 5)) # 5 seconds ago
|
|
|
+ time.sleep(1) # file2 must have newer timestamps than file1
|
|
|
self.create_regular_file('file2', size=1024 * 80)
|
|
|
self.cmd('init', '--encryption=repokey', self.repository_location)
|
|
|
output = self.cmd('create', '--list', self.repository_location + '::test', 'input')
|
|
@@ -1606,12 +1605,51 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|
|
# https://borgbackup.readthedocs.org/en/latest/faq.html#i-am-seeing-a-added-status-for-a-unchanged-file
|
|
|
self.assert_in("A input/file2", output)
|
|
|
|
|
|
+ def test_file_status_cs_cache_mode(self):
|
|
|
+ """test that a changed file with faked "previous" mtime still gets backed up in ctime,size cache_mode"""
|
|
|
+ self.create_regular_file('file1', contents=b'123')
|
|
|
+ time.sleep(1) # file2 must have newer timestamps than file1
|
|
|
+ self.create_regular_file('file2', size=10)
|
|
|
+ self.cmd('init', '--encryption=repokey', self.repository_location)
|
|
|
+ output = self.cmd('create', '--list', '--files-cache=ctime,size', self.repository_location + '::test1', 'input')
|
|
|
+ # modify file1, but cheat with the mtime (and atime) and also keep same size:
|
|
|
+ st = os.stat('input/file1')
|
|
|
+ self.create_regular_file('file1', contents=b'321')
|
|
|
+ os.utime('input/file1', ns=(st.st_atime_ns, st.st_mtime_ns))
|
|
|
+ # this mode uses ctime for change detection, so it should find file1 as modified
|
|
|
+ output = self.cmd('create', '--list', '--files-cache=ctime,size', self.repository_location + '::test2', 'input')
|
|
|
+ self.assert_in("A input/file1", output)
|
|
|
+
|
|
|
+ def test_file_status_ms_cache_mode(self):
|
|
|
+ """test that a chmod'ed file with no content changes does not get chunked again in mtime,size cache_mode"""
|
|
|
+ self.create_regular_file('file1', size=10)
|
|
|
+ time.sleep(1) # file2 must have newer timestamps than file1
|
|
|
+ self.create_regular_file('file2', size=10)
|
|
|
+ self.cmd('init', '--encryption=repokey', self.repository_location)
|
|
|
+ output = self.cmd('create', '--list', '--files-cache=mtime,size', self.repository_location + '::test1', 'input')
|
|
|
+ # change mode of file1, no content change:
|
|
|
+ st = os.stat('input/file1')
|
|
|
+ os.chmod('input/file1', st.st_mode ^ stat.S_IRWXO) # this triggers a ctime change, but mtime is unchanged
|
|
|
+ # this mode uses mtime for change detection, so it should find file1 as unmodified
|
|
|
+ output = self.cmd('create', '--list', '--files-cache=mtime,size', self.repository_location + '::test2', 'input')
|
|
|
+ self.assert_in("U input/file1", output)
|
|
|
+
|
|
|
+ def test_file_status_rc_cache_mode(self):
|
|
|
+ """test that files get rechunked unconditionally in rechunk,ctime cache mode"""
|
|
|
+ self.create_regular_file('file1', size=10)
|
|
|
+ time.sleep(1) # file2 must have newer timestamps than file1
|
|
|
+ self.create_regular_file('file2', size=10)
|
|
|
+ self.cmd('init', '--encryption=repokey', self.repository_location)
|
|
|
+ output = self.cmd('create', '--list', '--files-cache=rechunk,ctime', self.repository_location + '::test1', 'input')
|
|
|
+ # no changes here, but this mode rechunks unconditionally
|
|
|
+ output = self.cmd('create', '--list', '--files-cache=rechunk,ctime', self.repository_location + '::test2', 'input')
|
|
|
+ self.assert_in("A input/file1", output)
|
|
|
+
|
|
|
def test_file_status_excluded(self):
|
|
|
"""test that excluded paths are listed"""
|
|
|
|
|
|
- now = time.time()
|
|
|
self.create_regular_file('file1', size=1024 * 80)
|
|
|
- os.utime('input/file1', (now - 5, now - 5)) # 5 seconds ago
|
|
|
+ time.sleep(1) # file2 must have newer timestamps than file1
|
|
|
self.create_regular_file('file2', size=1024 * 80)
|
|
|
if has_lchflags:
|
|
|
self.create_regular_file('file3', size=1024 * 80)
|
|
@@ -1647,9 +1685,8 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|
|
assert 'stats' in archive
|
|
|
|
|
|
def test_create_topical(self):
|
|
|
- now = time.time()
|
|
|
self.create_regular_file('file1', size=1024 * 80)
|
|
|
- os.utime('input/file1', (now-5, now-5))
|
|
|
+ time.sleep(1) # file2 must have newer timestamps than file1
|
|
|
self.create_regular_file('file2', size=1024 * 80)
|
|
|
self.cmd('init', '--encryption=repokey', self.repository_location)
|
|
|
# no listing by default
|
|
@@ -2363,7 +2400,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
|
|
|
fd.write(b'b' * 280)
|
|
|
self.cmd('init', '--encryption=repokey', self.repository_location)
|
|
|
self.cmd('create', '--chunker-params', '7,9,8,128', self.repository_location + '::test1', 'input')
|
|
|
- self.cmd('create', self.repository_location + '::test2', 'input', '--no-files-cache')
|
|
|
+ self.cmd('create', self.repository_location + '::test2', 'input', '--files-cache=disabled')
|
|
|
list = self.cmd('list', self.repository_location + '::test1', 'input/large_file',
|
|
|
'--format', '{num_chunks} {unique_chunks}')
|
|
|
num_chunks, unique_chunks = map(int, list.split(' '))
|
|
@@ -3513,7 +3550,6 @@ class TestCommonOptions:
|
|
|
add_common_option('-p', '--progress', dest='progress', action='store_true', help='foo')
|
|
|
add_common_option('--lock-wait', dest='lock_wait', type=int, metavar='N', default=1,
|
|
|
help='(default: %(default)d).')
|
|
|
- add_common_option('--no-files-cache', dest='no_files_cache', action='store_false', help='foo')
|
|
|
|
|
|
@pytest.fixture
|
|
|
def basic_parser(self):
|
|
@@ -3555,7 +3591,6 @@ class TestCommonOptions:
|
|
|
|
|
|
def test_simple(self, parse_vars_from_line):
|
|
|
assert parse_vars_from_line('--error') == {
|
|
|
- 'no_files_cache': True,
|
|
|
'append': [],
|
|
|
'lock_wait': 1,
|
|
|
'log_level': 'error',
|
|
@@ -3563,7 +3598,6 @@ class TestCommonOptions:
|
|
|
}
|
|
|
|
|
|
assert parse_vars_from_line('--error', 'subcommand', '--critical') == {
|
|
|
- 'no_files_cache': True,
|
|
|
'append': [],
|
|
|
'lock_wait': 1,
|
|
|
'log_level': 'critical',
|
|
@@ -3576,7 +3610,6 @@ class TestCommonOptions:
|
|
|
parse_vars_from_line('--append-only', 'subcommand')
|
|
|
|
|
|
assert parse_vars_from_line('--append=foo', '--append', 'bar', 'subcommand', '--append', 'baz') == {
|
|
|
- 'no_files_cache': True,
|
|
|
'append': ['foo', 'bar', 'baz'],
|
|
|
'lock_wait': 1,
|
|
|
'log_level': 'warning',
|
|
@@ -3589,7 +3622,6 @@ class TestCommonOptions:
|
|
|
@pytest.mark.parametrize('flag,args_key,args_value', (
|
|
|
('-p', 'progress', True),
|
|
|
('--lock-wait=3', 'lock_wait', 3),
|
|
|
- ('--no-files-cache', 'no_files_cache', False),
|
|
|
))
|
|
|
def test_flag_position_independence(self, parse_vars_from_line, position, flag, args_key, args_value):
|
|
|
line = []
|
|
@@ -3600,7 +3632,6 @@ class TestCommonOptions:
|
|
|
line.append(flag)
|
|
|
|
|
|
result = {
|
|
|
- 'no_files_cache': True,
|
|
|
'append': [],
|
|
|
'lock_wait': 1,
|
|
|
'log_level': 'warning',
|