Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8711fa13a2 |
@@ -0,0 +1,149 @@
|
||||
name: platform builds
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
linux-compat:
|
||||
name: ${{ matrix.name }}
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: ubuntu-latest
|
||||
runner: ubuntu-latest
|
||||
run_tests: true
|
||||
- name: ubuntu-22.04
|
||||
runner: ubuntu-22.04
|
||||
run_tests: true
|
||||
- name: ubuntu-24.04-arm
|
||||
runner: ubuntu-24.04-arm
|
||||
run_tests: true
|
||||
- name: ubuntu-24.04-release
|
||||
runner: ubuntu-24.04
|
||||
buildtype: release
|
||||
- name: ubuntu-24.04-debug
|
||||
runner: ubuntu-24.04
|
||||
buildtype: debug
|
||||
- name: ubuntu-24.04-hardened
|
||||
runner: ubuntu-24.04
|
||||
extra_cflags: "-D_FORTIFY_SOURCE=3 -fstack-protector-strong"
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y gcc ninja-build pkg-config libglib2.0-dev libfuse3-dev ${{ matrix.run_tests && 'openssh-server openssh-client fuse3' || '' }}
|
||||
pip3 install meson ${{ matrix.run_tests && 'pytest pytest-timeout' || '' }}
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
CFLAGS: ${{ matrix.extra_cflags || '' }}
|
||||
run: |
|
||||
meson setup build ${{ matrix.buildtype && format('--buildtype={0}', matrix.buildtype) || '' }}
|
||||
ninja -C build
|
||||
|
||||
- name: Setup SSH
|
||||
if: matrix.run_tests
|
||||
run: |
|
||||
chmod go-w ~
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -q -N ""
|
||||
cat ~/.ssh/id_ed25519.pub > ~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
sudo sed -i 's/^#*PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
|
||||
sudo systemctl restart ssh || sudo service ssh restart
|
||||
ssh -o StrictHostKeyChecking=no -o BatchMode=yes localhost true
|
||||
|
||||
- name: Check FUSE availability
|
||||
if: matrix.run_tests
|
||||
run: |
|
||||
test -e /dev/fuse
|
||||
command -v fusermount3
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.run_tests
|
||||
timeout-minutes: 20
|
||||
run: |
|
||||
cd build
|
||||
python3 -m pytest test/ --timeout=300 --maxfail=99 --junitxml=test-results.xml
|
||||
|
||||
- name: Upload test results
|
||||
if: matrix.run_tests && always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: test-results-${{ matrix.name }}
|
||||
path: |
|
||||
build/test-results.xml
|
||||
build/meson-logs/
|
||||
|
||||
- name: Upload build logs
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: failure()
|
||||
with:
|
||||
name: build-logs-${{ matrix.name }}
|
||||
path: build/meson-logs/
|
||||
|
||||
alpine-musl:
|
||||
name: alpine-musl
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Build in Alpine container
|
||||
run: |
|
||||
docker run --rm -v "$PWD:/work" -w /work alpine:3.21@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d sh -euxc '
|
||||
apk add --no-cache gcc musl-dev meson ninja pkgconf glib-dev fuse3-dev
|
||||
meson setup build-alpine
|
||||
ninja -C build-alpine
|
||||
'
|
||||
|
||||
- name: Upload build logs
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: failure()
|
||||
with:
|
||||
name: build-logs-alpine-musl
|
||||
path: build-alpine/meson-logs/
|
||||
|
||||
freebsd:
|
||||
name: freebsd-14
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Build on FreeBSD
|
||||
uses: vmactions/freebsd-vm@d1e65811565151536c0c894fff74f06351ed26e6 # v1.4.5
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install -y fusefs-libs3 glib meson ninja pkgconf
|
||||
run: |
|
||||
meson setup build-freebsd
|
||||
ninja -C build-freebsd
|
||||
|
||||
- name: Upload build logs
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: failure()
|
||||
with:
|
||||
name: build-logs-freebsd
|
||||
path: build-freebsd/meson-logs/
|
||||
@@ -1,79 +0,0 @@
|
||||
name: valgrind
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
valgrind-memcheck:
|
||||
name: Valgrind memcheck
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 35
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: '3.12'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y valgrind gcc ninja-build libglib2.0-dev libfuse3-dev openssh-server openssh-client fuse3
|
||||
pip3 install meson pytest pytest-timeout
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
meson setup build
|
||||
ninja -C build
|
||||
|
||||
- name: Setup SSH
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
chmod 700 ~/.ssh
|
||||
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -q -N ""
|
||||
cat ~/.ssh/id_ed25519.pub > ~/.ssh/authorized_keys
|
||||
chmod 600 ~/.ssh/authorized_keys
|
||||
sudo systemctl start ssh || sudo service ssh start
|
||||
ssh -o StrictHostKeyChecking=no -o BatchMode=yes localhost true
|
||||
|
||||
- name: Check FUSE availability
|
||||
run: |
|
||||
test -e /dev/fuse
|
||||
command -v fusermount3
|
||||
|
||||
- name: Create Valgrind log directory
|
||||
run: mkdir -p valgrind-logs
|
||||
|
||||
- name: Run tests under Valgrind memcheck
|
||||
timeout-minutes: 30
|
||||
env:
|
||||
TEST_WITH_VALGRIND: "true"
|
||||
VALGRIND_OPTIONS: "--tool=memcheck --leak-check=full --show-leak-kinds=definite,indirect --errors-for-leak-kinds=definite,indirect --error-exitcode=99 --num-callers=25 --suppressions=${{ github.workspace }}/test/valgrind.supp --log-file=${{ github.workspace }}/valgrind-logs/memcheck.%p.log -q"
|
||||
G_DEBUG: "fatal-warnings,gc-friendly"
|
||||
G_SLICE: "always-malloc"
|
||||
run: |
|
||||
cd build
|
||||
python3 -m pytest -q --tb=short --maxfail=99 --timeout=300 \
|
||||
test/ \
|
||||
--junitxml=test-results-valgrind.xml
|
||||
|
||||
- name: Upload test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: test-results-valgrind
|
||||
path: |
|
||||
build/test-results-valgrind.xml
|
||||
build/meson-logs/
|
||||
valgrind-logs/
|
||||
@@ -1,5 +1,4 @@
|
||||
import sys
|
||||
import os
|
||||
import pytest
|
||||
import time
|
||||
import re
|
||||
@@ -86,13 +85,6 @@ def register_output(self, pattern, count=1, flags=re.MULTILINE):
|
||||
current_capfd = None
|
||||
|
||||
|
||||
_running_with_valgrind = os.environ.get("TEST_WITH_VALGRIND", "no").lower().strip() not in (
|
||||
"no",
|
||||
"false",
|
||||
"0",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def save_cap_fixtures(request, capfd):
|
||||
global current_capfd
|
||||
@@ -101,12 +93,6 @@ def save_cap_fixtures(request, capfd):
|
||||
# Monkeypatch in a function to register false positives
|
||||
type(capfd).register_output = register_output
|
||||
|
||||
# When running under Valgrind, its ==pid== summary lines on stderr are
|
||||
# expected. Register them as false positives so check_test_output does
|
||||
# not mistake them for suspicious output.
|
||||
if _running_with_valgrind:
|
||||
capfd.false_positives.append((r"^==[0-9]+==[^\n]*\n", re.MULTILINE, 0))
|
||||
|
||||
if request.config.getoption("capture") == "no":
|
||||
capfd = None
|
||||
current_capfd = capfd
|
||||
|
||||
+6
-19
@@ -9,14 +9,6 @@ from contextlib import contextmanager
|
||||
|
||||
basename = pjoin(os.path.dirname(__file__), "..")
|
||||
|
||||
_valgrind_timeout_multiplier = (
|
||||
4
|
||||
if os.environ.get("TEST_WITH_VALGRIND", "no").lower().strip()
|
||||
not in ("no", "false", "0")
|
||||
else 1
|
||||
)
|
||||
_mount_timeout = 30 * _valgrind_timeout_multiplier
|
||||
|
||||
|
||||
def os_create(name):
|
||||
os.close(os.open(name, os.O_CREAT | os.O_RDWR))
|
||||
@@ -33,7 +25,7 @@ def os_open(name, flags):
|
||||
|
||||
def wait_for_mount(mount_process, mnt_dir, test_fn=os.path.ismount):
|
||||
elapsed = 0
|
||||
while elapsed < _mount_timeout:
|
||||
while elapsed < 30:
|
||||
if test_fn(mnt_dir):
|
||||
return True
|
||||
if mount_process.poll() is not None:
|
||||
@@ -45,7 +37,7 @@ def wait_for_mount(mount_process, mnt_dir, test_fn=os.path.ismount):
|
||||
|
||||
def cleanup(mount_process, mnt_dir):
|
||||
subprocess.call(
|
||||
["fusermount3", "-z", "-u", mnt_dir],
|
||||
["fusermount", "-z", "-u", mnt_dir],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
@@ -63,7 +55,7 @@ def umount(mount_process, mnt_dir):
|
||||
# Give mount process a little while to terminate. Popen.wait(timeout)
|
||||
# was only added in 3.3...
|
||||
elapsed = 0
|
||||
while elapsed < _mount_timeout:
|
||||
while elapsed < 30:
|
||||
code = mount_process.poll()
|
||||
if code is not None:
|
||||
if code == 0:
|
||||
@@ -101,12 +93,12 @@ def fuse_test_marker():
|
||||
return pytest.mark.skip(reason=reason)
|
||||
|
||||
with subprocess.Popen(
|
||||
["which", "fusermount3"], stdout=subprocess.PIPE, universal_newlines=True
|
||||
["which", "fusermount"], stdout=subprocess.PIPE, universal_newlines=True
|
||||
) as which:
|
||||
fusermount_path = which.communicate()[0].strip()
|
||||
|
||||
if not fusermount_path or which.returncode != 0:
|
||||
return skip("Can't find fusermount3 executable")
|
||||
return skip("Can't find fusermount executable")
|
||||
|
||||
if not os.path.exists("/dev/fuse"):
|
||||
return skip("FUSE kernel module does not seem to be loaded")
|
||||
@@ -134,11 +126,6 @@ if os.environ.get("TEST_WITH_VALGRIND", "no").lower().strip() not in (
|
||||
"false",
|
||||
"0",
|
||||
):
|
||||
import shlex
|
||||
valgrind_options_env = os.environ.get("VALGRIND_OPTIONS", "")
|
||||
if valgrind_options_env:
|
||||
base_cmdline = ["valgrind"] + shlex.split(valgrind_options_env) + ["--"]
|
||||
else:
|
||||
base_cmdline = ["valgrind", "-q", "--"]
|
||||
base_cmdline = ["valgrind", "-q", "--"]
|
||||
else:
|
||||
base_cmdline = []
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# Valgrind suppression file for sshfs tests.
|
||||
#
|
||||
# Keep this file minimal. Only suppress stacks that originate entirely in
|
||||
# third-party libraries (GLib, libfuse, glibc, pthreads) and have been
|
||||
# confirmed as false positives or benign teardown noise.
|
||||
#
|
||||
# Do NOT suppress any stack frame that includes sshfs.c or cache.c unless
|
||||
# there is a documented upstream false positive with a linked note below.
|
||||
#
|
||||
# To generate candidates locally:
|
||||
# TEST_WITH_VALGRIND=true VALGRIND_OPTIONS="--tool=memcheck --leak-check=full \
|
||||
# --gen-suppressions=all -q --" python3 -m pytest test/test_sshfs.py ...
|
||||
|
||||
# libfuse allocates thread-local or worker-thread state inside its shared
|
||||
# library during pthread_create. These are not reachable after the threads
|
||||
# exit but are never explicitly freed — they are benign teardown leaks in
|
||||
# libfuse internals, not sshfs bugs.
|
||||
{
|
||||
libfuse-worker-thread-alloc
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: definite,indirect
|
||||
fun:calloc
|
||||
...
|
||||
obj:*/libfuse3.so*
|
||||
}
|
||||
Reference in New Issue
Block a user