Skip to content

Commit 968c454

Browse files
Merge pull request #9192 from ThomasWaldmann/backport-haiku-bsd-ci-1.4-maint
CI: backport vm_tests (FreeBSD/NetBSD/OpenBSD/Haiku) from master branch
2 parents b386060 + c43a78a commit 968c454

File tree

5 files changed

+210
-11
lines changed

5 files changed

+210
-11
lines changed

.github/workflows/ci.yml

Lines changed: 188 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ jobs:
113113
echo "Using LD_PRELOAD=$LD_PRELOAD"
114114
pytest -v --benchmark-skip -k "not remote"
115115
116-
posix_tests:
116+
native_tests:
117117

118118
needs: [lint]
119119
permissions:
@@ -254,3 +254,190 @@ jobs:
254254
name: ${{ matrix.binary }}
255255
path: artifacts/*
256256
if-no-files-found: error
257+
258+
vm_tests:
259+
260+
# Cross-OS tests running inside VMs, aligned with master branch structure.
261+
# Uses cross-platform-actions/action to run on FreeBSD, NetBSD, OpenBSD, Haiku.
262+
permissions:
263+
contents: read
264+
id-token: write
265+
attestations: write
266+
runs-on: ubuntu-24.04
267+
timeout-minutes: 90
268+
needs: [lint]
269+
continue-on-error: true
270+
strategy:
271+
fail-fast: false
272+
matrix:
273+
include:
274+
- os: freebsd
275+
version: '14.3'
276+
display_name: FreeBSD
277+
# Controls binary build and provenance attestation on tags
278+
do_binaries: true
279+
artifact_prefix: borg-freebsd-14-x86_64-gh
280+
- os: netbsd
281+
version: '10.1'
282+
display_name: NetBSD
283+
do_binaries: false
284+
- os: openbsd
285+
version: '7.7'
286+
display_name: OpenBSD
287+
do_binaries: false
288+
- os: haiku
289+
version: 'r1beta5'
290+
display_name: Haiku
291+
do_binaries: false
292+
293+
steps:
294+
- name: Check out repository
295+
uses: actions/checkout@v4
296+
with:
297+
fetch-depth: 0
298+
fetch-tags: true
299+
300+
- name: Test on ${{ matrix.display_name }}
301+
id: cross_os
302+
uses: cross-platform-actions/[email protected]
303+
env:
304+
DO_BINARIES: ${{ matrix.do_binaries }}
305+
with:
306+
operating_system: ${{ matrix.os }}
307+
version: ${{ matrix.version }}
308+
shell: bash
309+
run: |
310+
set -euxo pipefail
311+
case "${{ matrix.os }}" in
312+
freebsd)
313+
# Ensure a proper hostname/FQDN is set (VMs may not have one by default)
314+
sudo -E /bin/sh -c 'grep -q "freebsd\.local" /etc/hosts || echo "127.0.0.1 freebsd.local freebsd" >> /etc/hosts'
315+
sudo -E hostname freebsd.local
316+
hostname
317+
export IGNORE_OSVERSION=yes
318+
sudo -E pkg update -f
319+
sudo -E pkg install -y xxhash liblz4 zstd pkgconf
320+
# Install one of the FUSE libraries; fail if neither is available
321+
sudo -E pkg install -y fusefs-libs || sudo -E pkg install -y fusefs-libs3
322+
sudo -E pkg install -y rust
323+
sudo -E pkg install -y git
324+
sudo -E pkg install -y python310 py310-sqlite3
325+
sudo -E pkg install -y python311 py311-sqlite3 py311-pip py311-virtualenv
326+
sudo ln -sf /usr/local/bin/python3.11 /usr/local/bin/python3
327+
sudo ln -sf /usr/local/bin/python3.11 /usr/local/bin/python
328+
sudo ln -sf /usr/local/bin/pip3.11 /usr/local/bin/pip3
329+
sudo ln -sf /usr/local/bin/pip3.11 /usr/local/bin/pip
330+
python -m venv .venv
331+
. .venv/bin/activate
332+
python -V
333+
pip -V
334+
python -m pip install --upgrade pip wheel
335+
pip install -r requirements.d/development.txt
336+
pip install -e .
337+
tox -e py311-none
338+
if [[ "${{ matrix.do_binaries }}" == "true" && "${{ startsWith(github.ref, 'refs/tags/') }}" == "true" ]]; then
339+
python -m pip install 'pyinstaller==6.14.2'
340+
mkdir -p dist/binary
341+
pyinstaller --clean --distpath=dist/binary scripts/borg.exe.spec
342+
pushd dist/binary
343+
echo "single-file binary"
344+
chmod +x borg.exe
345+
./borg.exe -V
346+
echo "single-directory binary"
347+
chmod +x borg-dir/borg.exe
348+
./borg-dir/borg.exe -V
349+
tar czf borg.tgz borg-dir
350+
popd
351+
mkdir -p artifacts
352+
if [ -f dist/binary/borg.exe ]; then
353+
cp -v dist/binary/borg.exe artifacts/${{ matrix.artifact_prefix }}
354+
fi
355+
if [ -f dist/binary/borg.tgz ]; then
356+
cp -v dist/binary/borg.tgz artifacts/${{ matrix.artifact_prefix }}.tgz
357+
fi
358+
fi
359+
;;
360+
netbsd)
361+
# Ensure a proper hostname/FQDN is set (VMs may not have one by default)
362+
sudo -E /bin/sh -c 'grep -q "netbsd\.local" /etc/hosts || echo "127.0.0.1 netbsd.local netbsd" >> /etc/hosts'
363+
sudo -E hostname netbsd.local
364+
hostname
365+
arch="$(uname -m)"
366+
sudo -E mkdir -p /usr/pkg/etc/pkgin
367+
echo "http://ftp.NetBSD.org/pub/pkgsrc/packages/NetBSD/${arch}/10.1/All" | sudo tee /usr/pkg/etc/pkgin/repositories.conf > /dev/null
368+
sudo -E pkgin update
369+
sudo -E pkgin -y upgrade
370+
sudo -E pkgin -y install zstd lz4 xxhash git
371+
sudo -E pkgin -y install rust
372+
sudo -E pkgin -y install pkg-config
373+
sudo -E pkgin -y install py311-pip py311-virtualenv py311-tox
374+
sudo -E ln -sf /usr/pkg/bin/python3.11 /usr/pkg/bin/python3
375+
sudo -E ln -sf /usr/pkg/bin/pip3.11 /usr/pkg/bin/pip3
376+
sudo -E ln -sf /usr/pkg/bin/virtualenv-3.11 /usr/pkg/bin/virtualenv3
377+
sudo -E ln -sf /usr/pkg/bin/tox-3.11 /usr/pkg/bin/tox3
378+
# Ensure base system admin tools are on PATH for the non-root shell
379+
export PATH="/sbin:/usr/sbin:$PATH"
380+
echo "--- Preparing an extattr-enabled filesystem ---"
381+
# On many NetBSD setups /tmp is tmpfs without extended attributes.
382+
# Create a FFS image with extended attributes enabled and use it for TMPDIR.
383+
VNDDEV="vnd0"
384+
IMGFILE="/tmp/fs.img"
385+
sudo -E dd if=/dev/zero of=${IMGFILE} bs=1m count=1024
386+
sudo -E vndconfig -c "${VNDDEV}" "${IMGFILE}"
387+
sudo -E newfs -O 2ea /dev/r${VNDDEV}a
388+
MNT="/mnt/eafs"
389+
sudo -E mkdir -p ${MNT}
390+
sudo -E mount -t ffs -o extattr /dev/${VNDDEV}a $MNT
391+
export TMPDIR="${MNT}/tmp"
392+
sudo -E mkdir -p ${TMPDIR}
393+
sudo -E chmod 1777 ${TMPDIR}
394+
touch ${TMPDIR}/testfile
395+
lsextattr user ${TMPDIR}/testfile && echo "[xattr] *** xattrs SUPPORTED on ${TMPDIR}! ***"
396+
tox3 -e py311-none
397+
;;
398+
openbsd)
399+
sudo -E pkg_add xxhash lz4 zstd git
400+
sudo -E pkg_add rust
401+
sudo -E pkg_add openssl%3.4
402+
sudo -E pkg_add py3-pip py3-virtualenv py3-tox
403+
export BORG_OPENSSL_NAME=eopenssl34
404+
tox -e py312-none
405+
;;
406+
haiku)
407+
pkgman refresh
408+
pkgman install -y git pkgconfig zstd lz4 xxhash
409+
pkgman install -y openssl3
410+
pkgman install -y rust_bin
411+
pkgman install -y python3.10
412+
pkgman install -y cffi
413+
pkgman install -y lz4_devel zstd_devel xxhash_devel openssl3_devel libffi_devel
414+
# there is no pkgman package for tox, so we install it into a venv
415+
python3 -m ensurepip --upgrade
416+
python3 -m pip install --upgrade pip wheel
417+
python3 -m venv .venv
418+
. .venv/bin/activate
419+
export PKG_CONFIG_PATH="/system/develop/lib/pkgconfig:/system/lib/pkgconfig:${PKG_CONFIG_PATH:-}"
420+
export BORG_LIBLZ4_PREFIX=/system/develop
421+
export BORG_LIBZSTD_PREFIX=/system/develop
422+
export BORG_LIBXXHASH_PREFIX=/system/develop
423+
export BORG_OPENSSL_PREFIX=/system/develop
424+
pip install -r requirements.d/development.txt
425+
pip install -e .
426+
# troubles with either tox or pytest xdist, so we run pytest manually:
427+
pytest -v -rs --benchmark-skip -k "not remote and not socket"
428+
;;
429+
esac
430+
431+
- name: Upload artifacts
432+
if: startsWith(github.ref, 'refs/tags/') && matrix.do_binaries
433+
uses: actions/upload-artifact@v4
434+
with:
435+
name: ${{ matrix.os }}-${{ matrix.version }}-dist
436+
path: artifacts/*
437+
if-no-files-found: ignore
438+
439+
- name: Attest provenance
440+
if: startsWith(github.ref, 'refs/tags/') && matrix.do_binaries
441+
uses: actions/attest-build-provenance@v3
442+
with:
443+
subject-path: 'artifacts/*'

src/borg/platformflags.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@
99
is_win32 = sys.platform.startswith('win32')
1010
is_linux = sys.platform.startswith('linux')
1111
is_freebsd = sys.platform.startswith('freebsd')
12+
is_netbsd = sys.platform.startswith('netbsd')
13+
is_openbsd = sys.platform.startswith('openbsd')
1214
is_darwin = sys.platform.startswith('darwin')

src/borg/testsuite/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
# Does this version of llfuse support ns precision?
3131
have_fuse_mtime_ns = hasattr(llfuse.EntryAttributes, 'st_mtime_ns') if llfuse else False
3232

33+
has_mknod = hasattr(os, 'mknod')
34+
3335
try:
3436
from pytest import raises
3537
except: # noqa

src/borg/testsuite/archiver.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@
5656
from ..logger import setup_logging
5757
from ..remote import RemoteRepository, PathNotAllowed
5858
from ..repository import Repository
59-
from . import has_lchflags, llfuse
59+
from . import has_lchflags, has_mknod, llfuse
6060
from . import BaseTestCase, changedir, environment_variable, no_selinux, same_ts_ns, granularity_sleep
6161
from . import are_symlinks_supported, are_hardlinks_supported, are_fifos_supported, is_utime_fully_supported, is_birthtime_fully_supported
62-
from .platform import fakeroot_detected, is_darwin, is_freebsd, is_win32
62+
from .platform import fakeroot_detected, is_darwin, is_freebsd, is_netbsd, is_win32
6363
from .upgrader import make_attic_repo
6464
from . import key
6565

@@ -367,10 +367,11 @@ def create_test_files(self, create_hardlinks=True):
367367
if has_lchflags:
368368
platform.set_flags(os.path.join(self.input_path, 'flagfile'), stat.UF_NODUMP)
369369
try:
370-
# Block device
371-
os.mknod('input/bdev', 0o600 | stat.S_IFBLK, os.makedev(10, 20))
372-
# Char device
373-
os.mknod('input/cdev', 0o600 | stat.S_IFCHR, os.makedev(30, 40))
370+
if has_mknod:
371+
# Block device
372+
os.mknod('input/bdev', 0o600 | stat.S_IFBLK, os.makedev(10, 20))
373+
# Char device
374+
os.mknod('input/cdev', 0o600 | stat.S_IFCHR, os.makedev(30, 40))
374375
# File mode
375376
os.chmod('input/dir2', 0o555) # if we take away write perms, we need root to remove contents
376377
# File owner
@@ -426,8 +427,8 @@ def test_basic_functionality(self):
426427
expected.append('input/link1')
427428
if are_hardlinks_supported():
428429
expected.append('input/hardlink')
429-
if not have_root:
430-
# we could not create these device files without (fake)root
430+
if not have_root or not has_mknod:
431+
# we could not create these device files without (fake)root or without os.mknod
431432
expected.remove('input/bdev')
432433
expected.remove('input/cdev')
433434
if has_lchflags:
@@ -4879,7 +4880,10 @@ def get_changes(filename, data):
48794880
unexpected = {'type': 'modified', 'added': 0, 'removed': 0}
48804881
assert unexpected not in get_changes('input/file_touched', joutput)
48814882
if not content_only:
4882-
assert {"ctime", "mtime"}.issubset({c["type"] for c in get_changes('input/file_touched', joutput)})
4883+
# On Windows, ctime is the creation time and does not change on touch.
4884+
# NetBSD also only reports mtime here, see #8703 (backport of #9161 intent).
4885+
expected = {"mtime"} if (is_win32 or is_netbsd) else {"ctime", "mtime"}
4886+
assert expected.issubset({c["type"] for c in get_changes('input/file_touched', joutput)})
48834887
else:
48844888
# And if we're doing content-only, don't show the file at all.
48854889
assert not any(get_changes('input/file_touched', joutput))
@@ -5074,6 +5078,10 @@ def test_time_diffs(self):
50745078

50755079

50765080
@requires_hardlinks
5081+
@pytest.mark.skipif(
5082+
(not are_hardlinks_supported()) or is_freebsd or is_netbsd,
5083+
reason='Skip when hardlinks unsupported or on FreeBSD/NetBSD due to differing ctime/link handling; see #9147, #9153.',
5084+
)
50775085
def test_multiple_link_exclusion(self):
50785086
path_a = os.path.join(self.input_path, 'a')
50795087
path_b = os.path.join(self.input_path, 'b')

src/borg/testsuite/platform.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import tempfile
77
import unittest
88

9-
from ..platformflags import is_win32, is_linux, is_freebsd, is_darwin
9+
from ..platformflags import is_win32, is_linux, is_freebsd, is_netbsd, is_darwin
1010
from ..platform import acl_get, acl_set, swidth
1111
from ..platform import get_process_id, process_alive
1212
from . import BaseTestCase, unopened_tempfile

0 commit comments

Comments
 (0)