Skip to content

Commit 7329135

Browse files
Merge pull request #10535 from ThomasWaldmann/fix-win-local-tests
fix test failures on Windows with a non-UTC timezone / MSYS2 bash
2 parents b7383b5 + 5a78cf4 commit 7329135

5 files changed

Lines changed: 28 additions & 9 deletions

File tree

‎scripts/msys2-install-deps‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22

3-
pacman -S --needed --noconfirm git mingw-w64-ucrt-x86_64-{toolchain,pkgconf,lz4,openssl,rclone,python-msgpack,python-platformdirs,python,cython,python-setuptools,python-wheel,python-build,python-pkgconfig,python-packaging,python-pip,python-paramiko,rust,python-maturin}
3+
pacman -S --needed --noconfirm git mingw-w64-ucrt-x86_64-{toolchain,pkgconf,lz4,openssl,rclone,python-msgpack,python-platformdirs,python,cython,python-setuptools,python-setuptools-scm,python-wheel,python-build,python-pkgconfig,python-packaging,python-pip,python-paramiko,rust,python-maturin}
44

55
if [ "$1" = "development" ]; then
66
pacman -S --needed --noconfirm mingw-w64-ucrt-x86_64-python-{pytest,pytest-benchmark,pytest-cov,pytest-xdist}

‎src/borg/helpers/time.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ def parse_local_timestamp(timestamp, tzinfo=None):
2424
"""
2525
dt = datetime.fromisoformat(timestamp)
2626
if dt.tzinfo is None:
27-
dt = dt.astimezone(tz=tzinfo)
27+
try:
28+
dt = dt.astimezone(tz=tzinfo)
29+
except OSError as e:
30+
# e.g. win32 local time conversion fails for timestamps close to (or before) the epoch.
31+
raise ValueError(f"cannot convert {timestamp} to local time: {e}") from None
2832
return dt
2933

3034

‎src/borg/testsuite/archiver/completion_cmd_test.py‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -615,12 +615,14 @@ def test_completion_repo_is_a_directory(archivers, request, shell):
615615
def test_bash_repo_url_no_directories(archivers, request, tmp_path):
616616
archiver = request.getfixturevalue(archivers)
617617
(tmp_path / "somerepo").mkdir()
618-
for url in REPO_URLS:
619-
# a local directory looking like the start of the URL, so that plain directory completion finds it
620-
(tmp_path / url.split("/")[0]).mkdir(exist_ok=True)
618+
# local directories looking like the start of the URLs, so that plain directory completion finds them.
619+
# created by bash: on win32, MSYS2/Cygwin map the colon to a valid file name character.
620+
dirs = " ".join(sorted({url.split("/")[0] for url in REPO_URLS}))
621621
script = cmd(archiver, "completion", "bash")
622622
for url in REPO_URLS:
623-
result = _run_bash_completion_fn(script, f'cd "{tmp_path}"\n_borg_complete_repo_dirs "{url}"\n')
623+
result = _run_bash_completion_fn(
624+
script, f'cd "{tmp_path}"\nmkdir -p {dirs}\n_borg_complete_repo_dirs "{url}"\n'
625+
)
624626
assert result.returncode == 0, f"stderr: {result.stderr}"
625627
assert result.stdout == "", f"directories offered for {url}: {result.stdout}"
626628
result = _run_bash_completion_fn(script, f'cd "{tmp_path}"\n_borg_complete_repo_dirs some\n')

‎src/borg/testsuite/archiver/recreate_cmd_test.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,10 @@ def test_recreate_with_given_timestamp(archivers, request):
262262
# this shall recreate the archive with a different nominal timestamp.
263263
# --timestamp is the only change requested, so this also checks that a timestamp
264264
# change alone is enough to make recreate do the work instead of skipping the archive.
265-
cmd(archiver, "recreate", "-a", "test0", "--timestamp", "1970-01-02T00:00:00")
265+
# not 1970-01-02: win32 cannot convert that to local time east of UTC.
266+
cmd(archiver, "recreate", "-a", "test0", "--timestamp", "1970-01-03T00:00:00")
266267
info = cmd(archiver, "info", "-a", "test0").splitlines()
267-
dtime = datetime(1970, 1, 2, 0, 0, 0).astimezone() # local time in local timezone
268+
dtime = datetime(1970, 1, 3, 0, 0, 0).astimezone() # local time in local timezone
268269
s_time = dtime.strftime("%Y-%m-%d %H:%M:.. %z").replace("+", r"\+")
269270
assert any([re.search(r"Time \(nominal\).+ %s" % s_time, item) for item in info])
270271
# start/end time are just from the recreate operation

‎src/borg/testsuite/helpers/time_test.py‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33

44
from ...helpers.time import safe_ns, safe_s, safe_timestamp, SUPPORT_32BIT_PLATFORMS, calculate_relative_offset
55
from ...helpers.time import format_time, format_time_ns, OutputTimestamp
6-
from ...helpers.time import ns_to_pax_time, pax_time_to_ns
6+
from ...helpers.time import ns_to_pax_time, pax_time_to_ns, parse_local_timestamp
7+
from ...helpers import time as time_module
78

89

910
def utcfromtimestamp(timestamp):
@@ -107,3 +108,14 @@ def test_ns_to_pax_time(ns, expected):
107108
)
108109
def test_pax_time_to_ns(value, expected):
109110
assert pax_time_to_ns(value) == expected
111+
112+
113+
def test_parse_local_timestamp_oserror(monkeypatch):
114+
# win32 fails to convert 1970-01-02T00:00:00 to local time east of UTC.
115+
class FailingDatetime(datetime):
116+
def astimezone(self, tz=None):
117+
raise OSError(22, "Invalid argument")
118+
119+
monkeypatch.setattr(time_module, "datetime", FailingDatetime)
120+
with pytest.raises(ValueError, match="cannot convert 1970-01-02T00:00:00 to local time"):
121+
parse_local_timestamp("1970-01-02T00:00:00")

0 commit comments

Comments
 (0)