diff_cmd converted

This commit is contained in:
bigtedde 2023-07-04 17:15:15 -05:00
parent 99bf56cfcd
commit dfaea063a5
1 changed files with 263 additions and 281 deletions

View File

@ -2,22 +2,28 @@ import json
import os import os
import stat import stat
import time import time
import unittest
from ...constants import * # NOQA from ...constants import * # NOQA
from .. import are_symlinks_supported, are_hardlinks_supported from .. import are_symlinks_supported, are_hardlinks_supported
from ..platform import is_win32, is_darwin from ..platform import is_win32, is_darwin
from . import ArchiverTestCaseBase, RemoteArchiverTestCaseBase, ArchiverTestCaseBinaryBase, RK_ENCRYPTION, BORG_EXES from . import cmd, create_regular_file, RK_ENCRYPTION, assert_line_exists
class ArchiverTestCase(ArchiverTestCaseBase): def pytest_generate_tests(metafunc):
def test_basic_functionality(self): # Generates tests that run on local and remote repos, as well as with a binary base.
if "archivers" in metafunc.fixturenames:
metafunc.parametrize("archivers", ["archiver", "remote_archiver", "binary_archiver"])
def test_basic_functionality(archivers, request):
archiver = request.getfixturevalue(archivers)
repo_location, input_path = archiver.repository_location, archiver.input_path
# Setup files for the first snapshot # Setup files for the first snapshot
self.create_regular_file("empty", size=0) create_regular_file(input_path, "empty", size=0)
self.create_regular_file("file_unchanged", size=128) create_regular_file(input_path, "file_unchanged", size=128)
self.create_regular_file("file_removed", size=256) create_regular_file(input_path, "file_removed", size=256)
self.create_regular_file("file_removed2", size=512) create_regular_file(input_path, "file_removed2", size=512)
self.create_regular_file("file_replaced", size=1024) create_regular_file(input_path, "file_replaced", size=1024)
os.mkdir("input/dir_replaced_with_file") os.mkdir("input/dir_replaced_with_file")
os.chmod("input/dir_replaced_with_file", stat.S_IFDIR | 0o755) os.chmod("input/dir_replaced_with_file", stat.S_IFDIR | 0o755)
os.mkdir("input/dir_removed") os.mkdir("input/dir_removed")
@ -34,20 +40,20 @@ class ArchiverTestCase(ArchiverTestCaseBase):
os.link("input/file_removed", "input/hardlink_removed") os.link("input/file_removed", "input/hardlink_removed")
os.link("input/file_removed2", "input/hardlink_target_removed") os.link("input/file_removed2", "input/hardlink_target_removed")
self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
# Create the first snapshot # Create the first snapshot
self.cmd(f"--repo={self.repository_location}", "create", "test0", "input") cmd(archiver, f"--repo={repo_location}", "create", "test0", "input")
# Setup files for the second snapshot # Setup files for the second snapshot
self.create_regular_file("file_added", size=2048) create_regular_file(input_path, "file_added", size=2048)
self.create_regular_file("file_empty_added", size=0) create_regular_file(input_path, "file_empty_added", size=0)
os.unlink("input/file_replaced") os.unlink("input/file_replaced")
self.create_regular_file("file_replaced", contents=b"0" * 4096) create_regular_file(input_path, "file_replaced", contents=b"0" * 4096)
os.unlink("input/file_removed") os.unlink("input/file_removed")
os.unlink("input/file_removed2") os.unlink("input/file_removed2")
os.rmdir("input/dir_replaced_with_file") os.rmdir("input/dir_replaced_with_file")
self.create_regular_file("dir_replaced_with_file", size=8192) create_regular_file(input_path, "dir_replaced_with_file", size=8192)
os.chmod("input/dir_replaced_with_file", stat.S_IFREG | 0o755) os.chmod("input/dir_replaced_with_file", stat.S_IFREG | 0o755)
os.mkdir("input/dir_added") os.mkdir("input/dir_added")
os.rmdir("input/dir_removed") os.rmdir("input/dir_removed")
@ -58,7 +64,7 @@ class ArchiverTestCase(ArchiverTestCaseBase):
os.symlink("input/dir_added", "input/link_changed") os.symlink("input/dir_added", "input/link_changed")
os.symlink("input/dir_added", "input/link_added") os.symlink("input/dir_added", "input/link_added")
os.unlink("input/link_replaced_by_file") os.unlink("input/link_replaced_by_file")
self.create_regular_file("link_replaced_by_file", size=16384) create_regular_file(input_path, "link_replaced_by_file", size=16384)
os.unlink("input/link_removed") os.unlink("input/link_removed")
if are_hardlinks_supported(): if are_hardlinks_supported():
os.unlink("input/hardlink_removed") os.unlink("input/hardlink_removed")
@ -68,20 +74,20 @@ class ArchiverTestCase(ArchiverTestCaseBase):
fd.write(b"appended_data") fd.write(b"appended_data")
# Create the second snapshot # Create the second snapshot
self.cmd(f"--repo={self.repository_location}", "create", "test1a", "input") cmd(archiver, f"--repo={repo_location}", "create", "test1a", "input")
self.cmd(f"--repo={self.repository_location}", "create", "test1b", "input", "--chunker-params", "16,18,17,4095") cmd(archiver, f"--repo={repo_location}", "create", "test1b", "input", "--chunker-params", "16,18,17,4095")
def do_asserts(output, can_compare_ids, content_only=False): def do_asserts(output, can_compare_ids, content_only=False):
lines: list = output.splitlines() lines: list = output.splitlines()
assert "file_replaced" in output # added to debug #3494 assert "file_replaced" in output # added to debug #3494
change = "modified.*B" if can_compare_ids else r"modified: \(can't get size\)" change = "modified.*B" if can_compare_ids else r"modified: \(can't get size\)"
self.assert_line_exists(lines, f"{change}.*input/file_replaced") assert_line_exists(lines, f"{change}.*input/file_replaced")
# File unchanged # File unchanged
assert "input/file_unchanged" not in output assert "input/file_unchanged" not in output
# Directory replaced with a regular file # Directory replaced with a regular file
if "BORG_TESTS_IGNORE_MODES" not in os.environ and not is_win32 and not content_only: if "BORG_TESTS_IGNORE_MODES" not in os.environ and not is_win32 and not content_only:
self.assert_line_exists(lines, "[drwxr-xr-x -> -rwxr-xr-x].*input/dir_replaced_with_file") assert_line_exists(lines, "[drwxr-xr-x -> -rwxr-xr-x].*input/dir_replaced_with_file")
# Basic directory cases # Basic directory cases
assert "added directory input/dir_added" in output assert "added directory input/dir_added" in output
@ -89,9 +95,9 @@ class ArchiverTestCase(ArchiverTestCaseBase):
if are_symlinks_supported(): if are_symlinks_supported():
# Basic symlink cases # Basic symlink cases
self.assert_line_exists(lines, "changed link.*input/link_changed") assert_line_exists(lines, "changed link.*input/link_changed")
self.assert_line_exists(lines, "added link.*input/link_added") assert_line_exists(lines, "added link.*input/link_added")
self.assert_line_exists(lines, "removed link.*input/link_removed") assert_line_exists(lines, "removed link.*input/link_removed")
# Symlink replacing or being replaced # Symlink replacing or being replaced
if not content_only: if not content_only:
@ -105,9 +111,9 @@ class ArchiverTestCase(ArchiverTestCaseBase):
# should notice the changes in both links. However, the symlink # should notice the changes in both links. However, the symlink
# pointing to the file is not changed. # pointing to the file is not changed.
change = "modified.*0 B" if can_compare_ids else r"modified: \(can't get size\)" change = "modified.*0 B" if can_compare_ids else r"modified: \(can't get size\)"
self.assert_line_exists(lines, f"{change}.*input/empty") assert_line_exists(lines, f"{change}.*input/empty")
if are_hardlinks_supported(): if are_hardlinks_supported():
self.assert_line_exists(lines, f"{change}.*input/hardlink_contents_changed") assert_line_exists(lines, f"{change}.*input/hardlink_contents_changed")
if are_symlinks_supported(): if are_symlinks_supported():
assert "input/link_target_contents_changed" not in output assert "input/link_target_contents_changed" not in output
@ -221,26 +227,25 @@ class ArchiverTestCase(ArchiverTestCaseBase):
# its ctime. This should not be reflected in the output if content-only is set # its ctime. This should not be reflected in the output if content-only is set
assert not any(get_changes("input/hardlink_target_replaced", joutput)) assert not any(get_changes("input/hardlink_target_replaced", joutput))
output = self.cmd(f"--repo={self.repository_location}", "diff", "test0", "test1a") output = cmd(archiver, f"--repo={repo_location}", "diff", "test0", "test1a")
do_asserts(output, True) do_asserts(output, True)
# We expect exit_code=1 due to the chunker params warning # We expect exit_code=1 due to the chunker params warning
output = self.cmd( output = cmd(archiver, f"--repo={repo_location}", "diff", "test0", "test1b", "--content-only", exit_code=1)
f"--repo={self.repository_location}", "diff", "test0", "test1b", "--content-only", exit_code=1
)
do_asserts(output, False, content_only=True) do_asserts(output, False, content_only=True)
output = self.cmd(f"--repo={self.repository_location}", "diff", "test0", "test1a", "--json-lines") output = cmd(archiver, f"--repo={repo_location}", "diff", "test0", "test1a", "--json-lines")
do_json_asserts(output, True) do_json_asserts(output, True)
output = self.cmd( output = cmd(archiver, f"--repo={repo_location}", "diff", "test0", "test1a", "--json-lines", "--content-only")
f"--repo={self.repository_location}", "diff", "test0", "test1a", "--json-lines", "--content-only"
)
do_json_asserts(output, True, content_only=True) do_json_asserts(output, True, content_only=True)
def test_time_diffs(self):
self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION) def test_time_diffs(archivers, request):
self.create_regular_file("test_file", size=10) archiver = request.getfixturevalue(archivers)
self.cmd(f"--repo={self.repository_location}", "create", "archive1", "input") repo_location, input_path = archiver.repository_location, archiver.input_path
cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
create_regular_file(input_path, "test_file", size=10)
cmd(archiver, f"--repo={repo_location}", "create", "archive1", "input")
time.sleep(0.1) time.sleep(0.1)
os.unlink("input/test_file") os.unlink("input/test_file")
if is_win32: if is_win32:
@ -248,75 +253,52 @@ class ArchiverTestCase(ArchiverTestCaseBase):
time.sleep(15) time.sleep(15)
elif is_darwin: elif is_darwin:
time.sleep(1) # HFS has a 1s timestamp granularity time.sleep(1) # HFS has a 1s timestamp granularity
self.create_regular_file("test_file", size=15) create_regular_file(input_path, "test_file", size=15)
self.cmd(f"--repo={self.repository_location}", "create", "archive2", "input") cmd(archiver, f"--repo={repo_location}", "create", "archive2", "input")
output = self.cmd( output = cmd(
f"--repo={self.repository_location}", archiver, f"--repo={repo_location}", "diff", "archive1", "archive2", "--format", "'{mtime}{ctime} {path}{NL}'"
"diff",
"archive1",
"archive2",
"--format",
"'{mtime}{ctime} {path}{NL}'",
) )
self.assert_in("mtime", output) assert "mtime" in output
self.assert_in("ctime", output) # Should show up on windows as well since it is a new file. assert "ctime" in output # Should show up on Windows as well since it is a new file.
if is_darwin: if is_darwin:
time.sleep(1) # HFS has a 1s timestamp granularity time.sleep(1) # HFS has a 1s timestamp granularity
os.chmod("input/test_file", 0o777) os.chmod("input/test_file", 0o777)
self.cmd(f"--repo={self.repository_location}", "create", "archive3", "input") cmd(archiver, f"--repo={repo_location}", "create", "archive3", "input")
output = self.cmd( output = cmd(
f"--repo={self.repository_location}", archiver, f"--repo={repo_location}", "diff", "archive2", "archive3", "--format", "'{mtime}{ctime} {path}{NL}'"
"diff",
"archive2",
"archive3",
"--format",
"'{mtime}{ctime} {path}{NL}'",
) )
self.assert_not_in("mtime", output) assert "mtime" not in output
# Checking platform because ctime should not be shown on windows since it wasn't recreated. # Checking platform because ctime should not be shown on Windows since it wasn't recreated.
if not is_win32: if not is_win32:
self.assert_in("ctime", output) assert "ctime" in output
else: else:
self.assert_not_in("ctime", output) assert "ctime" not in output
def test_sort_option(self):
self.cmd(f"--repo={self.repository_location}", "rcreate", RK_ENCRYPTION)
self.create_regular_file("a_file_removed", size=8) def test_sort_option(archivers, request):
self.create_regular_file("f_file_removed", size=16) archiver = request.getfixturevalue(archivers)
self.create_regular_file("c_file_changed", size=32) repo_location, input_path = archiver.repository_location, archiver.input_path
self.create_regular_file("e_file_changed", size=64) cmd(archiver, f"--repo={repo_location}", "rcreate", RK_ENCRYPTION)
self.cmd(f"--repo={self.repository_location}", "create", "test0", "input")
create_regular_file(input_path, "a_file_removed", size=8)
create_regular_file(input_path, "f_file_removed", size=16)
create_regular_file(input_path, "c_file_changed", size=32)
create_regular_file(input_path, "e_file_changed", size=64)
cmd(archiver, f"--repo={repo_location}", "create", "test0", "input")
os.unlink("input/a_file_removed") os.unlink("input/a_file_removed")
os.unlink("input/f_file_removed") os.unlink("input/f_file_removed")
os.unlink("input/c_file_changed") os.unlink("input/c_file_changed")
os.unlink("input/e_file_changed") os.unlink("input/e_file_changed")
self.create_regular_file("c_file_changed", size=512) create_regular_file(input_path, "c_file_changed", size=512)
self.create_regular_file("e_file_changed", size=1024) create_regular_file(input_path, "e_file_changed", size=1024)
self.create_regular_file("b_file_added", size=128) create_regular_file(input_path, "b_file_added", size=128)
self.create_regular_file("d_file_added", size=256) create_regular_file(input_path, "d_file_added", size=256)
self.cmd(f"--repo={self.repository_location}", "create", "test1", "input") cmd(archiver, f"--repo={repo_location}", "create", "test1", "input")
output = self.cmd(f"--repo={self.repository_location}", "diff", "test0", "test1", "--sort", "--content-only") output = cmd(archiver, f"--repo={repo_location}", "diff", "test0", "test1", "--sort", "--content-only")
expected = [ expected = ["a_file_removed", "b_file_added", "c_file_changed", "d_file_added", "e_file_changed", "f_file_removed"]
"a_file_removed",
"b_file_added",
"c_file_changed",
"d_file_added",
"e_file_changed",
"f_file_removed",
]
assert isinstance(output, str) assert isinstance(output, str)
outputs = output.splitlines() outputs = output.splitlines()
assert len(outputs) == len(expected) assert len(outputs) == len(expected)
assert all(x in line for x, line in zip(expected, outputs)) assert all(x in line for x, line in zip(expected, outputs))
class RemoteArchiverTestCase(RemoteArchiverTestCaseBase, ArchiverTestCase):
"""run the same tests, but with a remote repository"""
@unittest.skipUnless("binary" in BORG_EXES, "no borg.exe available")
class ArchiverTestCaseBinary(ArchiverTestCaseBinaryBase, ArchiverTestCase):
"""runs the same tests, but via the borg binary"""