mirror of
https://github.com/koverstreet/bcachefs-tools.git
synced 2025-01-22 00:04:31 +03:00
kill old python tests
these were never used, kill a dependency Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
07913d1185
commit
9020d202a4
11
Makefile
11
Makefile
@ -152,9 +152,6 @@ all: bcachefs $(optional_build)
|
||||
debug: CFLAGS+=-Werror -DCONFIG_BCACHEFS_DEBUG=y -DCONFIG_VALGRIND=y
|
||||
debug: bcachefs
|
||||
|
||||
.PHONY: tests
|
||||
tests: tests/test_helper
|
||||
|
||||
.PHONY: TAGS tags
|
||||
TAGS:
|
||||
ctags -e -R .
|
||||
@ -178,14 +175,10 @@ RUST_SRCS:=$(shell find src bch_bindgen/src -type f -iname '*.rs')
|
||||
bcachefs: $(BCACHEFS_DEPS) $(RUST_SRCS)
|
||||
$(Q)$(CARGO_BUILD)
|
||||
|
||||
libbcachefs.a: $(filter-out ./tests/%.o, $(OBJS))
|
||||
libbcachefs.a: $(OBJS)
|
||||
@echo " [AR] $@"
|
||||
$(Q)$(AR) -rc $@ $+
|
||||
|
||||
tests/test_helper: $(filter ./tests/%.o, $(OBJS))
|
||||
@echo " [LD] $@"
|
||||
$(Q)$(CC) $(LDFLAGS) $+ $(LOADLIBES) $(LDLIBS) -o $@
|
||||
|
||||
# If the version string differs from the last build, update the last version
|
||||
ifneq ($(VERSION),$(shell cat .version 2>/dev/null))
|
||||
.PHONY: .version
|
||||
@ -225,7 +218,7 @@ install_systemd: $(systemd_services) $(systemd_libexecfiles)
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning all"
|
||||
$(Q)$(RM) libbcachefs.a c_src/libbcachefs.a tests/test_helper .version *.tar.xz $(OBJS) $(DEPS) $(DOCGENERATED)
|
||||
$(Q)$(RM) libbcachefs.a c_src/libbcachefs.a .version *.tar.xz $(OBJS) $(DEPS) $(DOCGENERATED)
|
||||
$(Q)$(CARGO_CLEAN)
|
||||
$(Q)$(RM) -f $(built_scripts)
|
||||
|
||||
|
1
debian/control
vendored
1
debian/control
vendored
@ -9,7 +9,6 @@ Build-Depends: debhelper-compat (= 13),
|
||||
python3:native,
|
||||
pkgconf,
|
||||
python3-docutils,
|
||||
python3-pytest,
|
||||
libaio-dev,
|
||||
libfuse3-dev,
|
||||
libblkid-dev,
|
||||
|
@ -1,18 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# pytest fixture definitions.
|
||||
|
||||
import pytest
|
||||
from tests import util
|
||||
|
||||
@pytest.fixture
|
||||
def bfuse(tmpdir):
|
||||
'''A test requesting a "bfuse" is given one via this fixture.'''
|
||||
|
||||
dev = util.format_1g(tmpdir)
|
||||
mnt = util.mountpoint(tmpdir)
|
||||
bf = util.BFuse(dev, mnt)
|
||||
|
||||
yield bf
|
||||
|
||||
bf.unmount(timeout=5.0)
|
@ -1,67 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Basic bcachefs functionality tests.
|
||||
|
||||
import re
|
||||
from tests import util
|
||||
|
||||
def test_help():
|
||||
ret = util.run_bch(valgrind=True)
|
||||
|
||||
assert ret.returncode == 1
|
||||
assert "missing command" in ret.stdout
|
||||
assert len(ret.stderr) == 0
|
||||
|
||||
def test_format(tmpdir):
|
||||
dev = util.device_1g(tmpdir)
|
||||
ret = util.run_bch('format', dev, valgrind=True)
|
||||
|
||||
assert ret.returncode == 0
|
||||
assert len(ret.stdout) > 0
|
||||
assert len(ret.stderr) == 0
|
||||
|
||||
def test_fsck(tmpdir):
|
||||
dev = util.format_1g(tmpdir)
|
||||
|
||||
ret = util.run_bch('fsck', dev, valgrind=True)
|
||||
|
||||
assert ret.returncode == 0
|
||||
assert len(ret.stdout) > 0
|
||||
assert len(ret.stderr) == 0
|
||||
|
||||
def test_list(tmpdir):
|
||||
dev = util.format_1g(tmpdir)
|
||||
|
||||
ret = util.run_bch('list', dev, valgrind=True)
|
||||
|
||||
assert ret.returncode == 0
|
||||
assert len(ret.stderr) == 0
|
||||
assert "recovering from clean shutdown" in ret.stdout
|
||||
|
||||
def test_list_inodes(tmpdir):
|
||||
dev = util.format_1g(tmpdir)
|
||||
|
||||
ret = util.run_bch('list', '-b', 'inodes', dev, valgrind=True)
|
||||
|
||||
assert ret.returncode == 0
|
||||
assert len(ret.stderr) == 0
|
||||
assert len(ret.stdout.splitlines()) == (67)
|
||||
|
||||
def test_list_dirent(tmpdir):
|
||||
dev = util.format_1g(tmpdir)
|
||||
|
||||
ret = util.run_bch('list', '-b', 'dirents', dev, valgrind=True)
|
||||
|
||||
assert ret.returncode == 0
|
||||
assert len(ret.stderr) == 0
|
||||
assert len(ret.stdout.splitlines()) == (6) # See example:
|
||||
|
||||
# Example:
|
||||
# mounting version 1.6: btree_subvolume_children opts=ro,errors=continue,degraded,nochanges,norecovery,read_only
|
||||
# recovering from clean shutdown, journal seq 9
|
||||
# alloc_read... done
|
||||
# stripes_read... done
|
||||
# snapshots_read... done
|
||||
# u64s 8 type dirent 4096:453699834857023875:U32_MAX len 0 ver 0: lost+found -> 4097 type dir
|
||||
last = ret.stdout.splitlines()[0]
|
||||
assert re.match(r'^.*type dirent.*: lost\+found ->.*$', last)
|
@ -1,74 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Tests of the functions in util.py
|
||||
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from tests import util
|
||||
|
||||
helper = os.path.abspath(os.path.join(util.BASE_PATH, 'test_helper'))
|
||||
|
||||
def test_sparse_file(tmpdir):
|
||||
dev = util.sparse_file(tmpdir / '1k', 1024)
|
||||
assert dev.stat().st_size == 1024
|
||||
|
||||
def test_device_1g(tmpdir):
|
||||
dev = util.device_1g(tmpdir)
|
||||
assert dev.stat().st_size == 1024**3
|
||||
|
||||
def test_abort():
|
||||
ret = util.run(helper, 'abort')
|
||||
assert ret.returncode == -signal.SIGABRT
|
||||
|
||||
def test_segfault():
|
||||
ret = util.run(helper, 'segfault')
|
||||
assert ret.returncode == -signal.SIGSEGV
|
||||
|
||||
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
|
||||
def test_check():
|
||||
with pytest.raises(subprocess.CalledProcessError):
|
||||
util.run(helper, 'abort', check=True)
|
||||
|
||||
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
|
||||
def test_leak():
|
||||
with pytest.raises(util.ValgrindFailedError):
|
||||
util.run(helper, 'leak', valgrind=True)
|
||||
|
||||
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
|
||||
def test_undefined():
|
||||
with pytest.raises(util.ValgrindFailedError):
|
||||
util.run(helper, 'undefined', valgrind=True)
|
||||
|
||||
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
|
||||
def test_undefined_branch():
|
||||
with pytest.raises(util.ValgrindFailedError):
|
||||
util.run(helper, 'undefined_branch', valgrind=True)
|
||||
|
||||
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
|
||||
def test_read_after_free():
|
||||
with pytest.raises(util.ValgrindFailedError):
|
||||
util.run(helper, 'read_after_free', valgrind=True)
|
||||
|
||||
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
|
||||
def test_write_after_free():
|
||||
with pytest.raises(util.ValgrindFailedError):
|
||||
util.run(helper, 'write_after_free', valgrind=True)
|
||||
|
||||
def test_mountpoint(tmpdir):
|
||||
path = util.mountpoint(tmpdir)
|
||||
assert str(path)[-4:] == '/mnt'
|
||||
assert path.is_dir()
|
||||
|
||||
def test_timestamp():
|
||||
t1 = time.clock_gettime(time.CLOCK_REALTIME)
|
||||
with util.Timestamp() as ts:
|
||||
t2 = time.clock_gettime(time.CLOCK_REALTIME)
|
||||
t3 = time.clock_gettime(time.CLOCK_REALTIME)
|
||||
|
||||
assert not ts.contains(t1)
|
||||
assert ts.contains(t2)
|
||||
assert not ts.contains(t3)
|
@ -1,236 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
#
|
||||
# Tests of the fuse mount functionality.
|
||||
|
||||
import pytest
|
||||
import os
|
||||
from tests import util
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
not util.have_fuse(), reason="bcachefs not built with fuse support.")
|
||||
|
||||
def test_mount(bfuse):
|
||||
bfuse.mount()
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
@pytest.mark.skipif(util.ENABLE_VALGRIND, reason="test broken")
|
||||
def test_remount(bfuse):
|
||||
bfuse.mount()
|
||||
bfuse.unmount()
|
||||
bfuse.mount()
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_lostfound(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
lf = bfuse.mnt / "lost+found"
|
||||
assert lf.is_dir()
|
||||
|
||||
st = lf.stat()
|
||||
assert st.st_mode == 0o40700
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_create(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
path = bfuse.mnt / "file"
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
fd = os.open(path, os.O_CREAT, 0o700)
|
||||
|
||||
assert fd >= 0
|
||||
|
||||
os.close(fd)
|
||||
assert path.is_file()
|
||||
|
||||
# Verify file.
|
||||
st = path.stat()
|
||||
assert st.st_mode == 0o100700
|
||||
assert st.st_mtime == st.st_ctime
|
||||
assert st.st_mtime == st.st_atime
|
||||
assert ts.contains(st.st_mtime)
|
||||
|
||||
# Verify dir.
|
||||
dst = bfuse.mnt.stat()
|
||||
assert dst.st_mtime == dst.st_ctime
|
||||
assert ts.contains(dst.st_mtime)
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_mkdir(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
path = bfuse.mnt / "dir"
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
os.mkdir(path, 0o700)
|
||||
|
||||
assert path.is_dir()
|
||||
|
||||
# Verify child.
|
||||
st = path.stat()
|
||||
assert st.st_mode == 0o40700
|
||||
assert st.st_mtime == st.st_ctime
|
||||
assert st.st_mtime == st.st_atime
|
||||
assert ts.contains(st.st_mtime)
|
||||
|
||||
# Verify parent.
|
||||
dst = bfuse.mnt.stat()
|
||||
assert dst.st_mtime == dst.st_ctime
|
||||
assert ts.contains(dst.st_mtime)
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_unlink(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
path = bfuse.mnt / "file"
|
||||
path.touch(mode=0o600, exist_ok=False)
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
os.unlink(path)
|
||||
|
||||
assert not path.exists()
|
||||
|
||||
# Verify dir.
|
||||
dst = bfuse.mnt.stat()
|
||||
assert dst.st_mtime == dst.st_ctime
|
||||
assert ts.contains(dst.st_mtime)
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_rmdir(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
path = bfuse.mnt / "dir"
|
||||
path.mkdir(mode=0o700, exist_ok=False)
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
os.rmdir(path)
|
||||
|
||||
assert not path.exists()
|
||||
|
||||
# Verify dir.
|
||||
dst = bfuse.mnt.stat()
|
||||
assert dst.st_mtime == dst.st_ctime
|
||||
assert ts.contains(dst.st_mtime)
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_rename(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
srcdir = bfuse.mnt
|
||||
|
||||
path = srcdir / "file"
|
||||
path.touch(mode=0o600, exist_ok=False)
|
||||
|
||||
destdir = srcdir / "dir"
|
||||
destdir.mkdir(mode=0o700, exist_ok=False)
|
||||
|
||||
destpath = destdir / "file"
|
||||
|
||||
path_pre_st = path.stat()
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
os.rename(path, destpath)
|
||||
|
||||
assert not path.exists()
|
||||
assert destpath.is_file()
|
||||
|
||||
# Verify dirs.
|
||||
src_st = srcdir.stat()
|
||||
assert src_st.st_mtime == src_st.st_ctime
|
||||
assert ts.contains(src_st.st_mtime)
|
||||
|
||||
dest_st = destdir.stat()
|
||||
assert dest_st.st_mtime == dest_st.st_ctime
|
||||
assert ts.contains(dest_st.st_mtime)
|
||||
|
||||
# Verify file.
|
||||
path_post_st = destpath.stat()
|
||||
assert path_post_st.st_mtime == path_pre_st.st_mtime
|
||||
assert path_post_st.st_atime == path_pre_st.st_atime
|
||||
assert ts.contains(path_post_st.st_ctime)
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_link(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
srcdir = bfuse.mnt
|
||||
|
||||
path = srcdir / "file"
|
||||
path.touch(mode=0o600, exist_ok=False)
|
||||
|
||||
destdir = srcdir / "dir"
|
||||
destdir.mkdir(mode=0o700, exist_ok=False)
|
||||
|
||||
destpath = destdir / "file"
|
||||
|
||||
path_pre_st = path.stat()
|
||||
srcdir_pre_st = srcdir.stat()
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
os.link(path, destpath)
|
||||
|
||||
assert path.exists()
|
||||
assert destpath.is_file()
|
||||
|
||||
# Verify source dir is unchanged.
|
||||
srcdir_post_st = srcdir.stat()
|
||||
assert srcdir_pre_st == srcdir_post_st
|
||||
|
||||
# Verify dest dir.
|
||||
destdir_st = destdir.stat()
|
||||
assert destdir_st.st_mtime == destdir_st.st_ctime
|
||||
assert ts.contains(destdir_st.st_mtime)
|
||||
|
||||
# Verify file.
|
||||
path_post_st = path.stat()
|
||||
destpath_post_st = destpath.stat()
|
||||
assert path_post_st == destpath_post_st
|
||||
|
||||
assert path_post_st.st_mtime == path_pre_st.st_mtime
|
||||
assert path_post_st.st_atime == path_pre_st.st_atime
|
||||
assert ts.contains(path_post_st.st_ctime)
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
||||
|
||||
def test_write(bfuse):
|
||||
bfuse.mount()
|
||||
|
||||
path = bfuse.mnt / "file"
|
||||
path.touch(mode=0o600, exist_ok=False)
|
||||
|
||||
pre_st = path.stat()
|
||||
|
||||
fd = os.open(path, os.O_WRONLY)
|
||||
assert fd >= 0
|
||||
|
||||
with util.Timestamp() as ts:
|
||||
written = os.write(fd, b'test')
|
||||
|
||||
os.close(fd)
|
||||
|
||||
assert written == 4
|
||||
|
||||
post_st = path.stat()
|
||||
assert post_st.st_atime == pre_st.st_atime
|
||||
assert post_st.st_mtime == post_st.st_ctime
|
||||
assert ts.contains(post_st.st_mtime)
|
||||
|
||||
assert path.read_bytes() == b'test'
|
||||
|
||||
bfuse.unmount()
|
||||
bfuse.verify()
|
@ -1,103 +0,0 @@
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void trick_compiler(int *x);
|
||||
|
||||
static void test_abort(void)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static void test_segfault(void)
|
||||
{
|
||||
raise(SIGSEGV);
|
||||
}
|
||||
|
||||
static void test_leak(void)
|
||||
{
|
||||
int *p = malloc(sizeof *p);
|
||||
trick_compiler(p);
|
||||
}
|
||||
|
||||
static void test_undefined(void)
|
||||
{
|
||||
int *p = malloc(1);
|
||||
printf("%d\n", *p);
|
||||
}
|
||||
|
||||
static void test_undefined_branch(void)
|
||||
{
|
||||
int x;
|
||||
trick_compiler(&x);
|
||||
|
||||
if (x)
|
||||
printf("1\n");
|
||||
else
|
||||
printf("0\n");
|
||||
}
|
||||
|
||||
static void test_read_after_free(void)
|
||||
{
|
||||
int *p = malloc(sizeof *p);
|
||||
free(p);
|
||||
|
||||
printf("%d\n", *p);
|
||||
}
|
||||
|
||||
static void test_write_after_free(void)
|
||||
{
|
||||
int *p = malloc(sizeof *p);
|
||||
free(p);
|
||||
|
||||
printf("%d\n", *p);
|
||||
}
|
||||
|
||||
typedef void (*test_fun)(void);
|
||||
|
||||
struct test {
|
||||
const char *name;
|
||||
test_fun fun;
|
||||
};
|
||||
|
||||
#define TEST(f) { .name = #f, .fun = test_##f, }
|
||||
static struct test tests[] = {
|
||||
TEST(abort),
|
||||
TEST(segfault),
|
||||
TEST(leak),
|
||||
TEST(undefined),
|
||||
TEST(undefined_branch),
|
||||
TEST(read_after_free),
|
||||
TEST(write_after_free),
|
||||
};
|
||||
#define ntests (sizeof tests / sizeof *tests)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "Usage: test_helper <test>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
for (i = 0; i < ntests; ++i)
|
||||
if (!strcmp(argv[1], tests[i].name)) {
|
||||
found = true;
|
||||
printf("Running test: %s\n", tests[i].name);
|
||||
tests[i].fun();
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
fprintf(stderr, "Unable to find test: %s\n", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
/*
|
||||
* Prevent compiler from optimizing away a variable by referencing it from
|
||||
* another compilation unit.
|
||||
*/
|
||||
void
|
||||
trick_compiler(int *x)
|
||||
{
|
||||
}
|
257
tests/util.py
257
tests/util.py
@ -1,257 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
BASE_PATH= os.path.dirname(__file__)
|
||||
BCH_PATH = os.path.abspath(os.path.join(BASE_PATH, '../target/release', 'bcachefs'))
|
||||
VALGRIND_PATH= os.path.abspath(os.path.join(BASE_PATH,
|
||||
'valgrind-suppressions.txt'))
|
||||
|
||||
VPAT = re.compile(r'ERROR SUMMARY: (\d+) errors from (\d+) contexts')
|
||||
|
||||
ENABLE_VALGRIND = os.getenv('BCACHEFS_TEST_USE_VALGRIND', 'no') == 'yes'
|
||||
|
||||
class ValgrindFailedError(Exception):
|
||||
def __init__(self, log):
|
||||
self.log = log
|
||||
|
||||
def check_valgrind(log):
|
||||
m = VPAT.search(log)
|
||||
if m is None:
|
||||
print('Internal error: valgrind log did not match.')
|
||||
print('-- valgrind log:')
|
||||
print(log)
|
||||
print('-- end log --')
|
||||
assert False
|
||||
|
||||
errors = int(m.group(1))
|
||||
if errors > 0:
|
||||
raise ValgrindFailedError(log)
|
||||
|
||||
def run(cmd, *args, valgrind=False, check=False):
|
||||
"""Run an external program via subprocess, optionally with valgrind.
|
||||
|
||||
This subprocess wrapper will capture the stdout and stderr. If valgrind is
|
||||
requested, it will be checked for errors and raise a
|
||||
ValgrindFailedError if there's a problem.
|
||||
"""
|
||||
cmds = [cmd] + list(args)
|
||||
valgrind = valgrind and ENABLE_VALGRIND
|
||||
|
||||
print("Running '{}'".format(cmds))
|
||||
if valgrind:
|
||||
vout = tempfile.NamedTemporaryFile()
|
||||
vcmd = ['valgrind',
|
||||
'--leak-check=full',
|
||||
'--gen-suppressions=all',
|
||||
'--suppressions={}'.format(VALGRIND_PATH),
|
||||
'--log-file={}'.format(vout.name)]
|
||||
cmds = vcmd + cmds
|
||||
|
||||
res = subprocess.run(cmds, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, encoding='utf-8', check=check)
|
||||
check_valgrind(vout.read().decode('utf-8'))
|
||||
else:
|
||||
res = subprocess.run(cmds, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, encoding='utf-8', check=check)
|
||||
|
||||
return res
|
||||
|
||||
def run_bch(*args, **kwargs):
|
||||
"""Wrapper to run the bcachefs binary specifically."""
|
||||
cmds = [BCH_PATH] + list(args)
|
||||
return run(*cmds, **kwargs)
|
||||
|
||||
def sparse_file(lpath, size):
|
||||
"""Construct a sparse file of the specified size.
|
||||
|
||||
This is typically used to create device files for bcachefs.
|
||||
"""
|
||||
path = Path(lpath)
|
||||
path.touch(mode = 0o600, exist_ok = False)
|
||||
os.truncate(path, size)
|
||||
|
||||
return path
|
||||
|
||||
def device_1g(tmpdir):
|
||||
"""Default 1g sparse file for use with bcachefs."""
|
||||
path = tmpdir / 'dev-1g'
|
||||
return sparse_file(path, 1024**3)
|
||||
|
||||
def format_1g(tmpdir):
|
||||
"""Format a default filesystem on a 1g device."""
|
||||
dev = device_1g(tmpdir)
|
||||
run_bch('format', dev, check=True)
|
||||
return dev
|
||||
|
||||
def mountpoint(tmpdir):
|
||||
"""Construct a mountpoint "mnt" for tests."""
|
||||
path = Path(tmpdir) / 'mnt'
|
||||
path.mkdir(mode = 0o700)
|
||||
return path
|
||||
|
||||
class Timestamp:
|
||||
'''Context manager to assist in verifying timestamps.
|
||||
|
||||
Records the range of times which would be valid for an encoded operation to
|
||||
use.
|
||||
|
||||
FIXME: The kernel code is currently using CLOCK_REALTIME_COARSE, but python
|
||||
didn't expose this time API (yet). Probably the kernel shouldn't be using
|
||||
_COARSE anyway, but this might lead to occasional errors.
|
||||
|
||||
To make sure this doesn't happen, we sleep a fraction of a second in an
|
||||
attempt to guarantee containment.
|
||||
|
||||
N.B. this might be better tested by overriding the clock used in bcachefs.
|
||||
|
||||
'''
|
||||
def __init__(self):
|
||||
self.start = None
|
||||
self.end = None
|
||||
|
||||
def __enter__(self):
|
||||
self.start = time.clock_gettime(time.CLOCK_REALTIME)
|
||||
time.sleep(0.1)
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
time.sleep(0.1)
|
||||
self.end = time.clock_gettime(time.CLOCK_REALTIME)
|
||||
|
||||
def contains(self, test):
|
||||
'''True iff the test time is within the range.'''
|
||||
return self.start <= test <= self.end
|
||||
|
||||
class FuseError(Exception):
|
||||
def __init__(self, msg):
|
||||
self.msg = msg
|
||||
|
||||
class BFuse:
|
||||
'''bcachefs fuse runner.
|
||||
|
||||
This class runs bcachefs in fusemount mode, and waits until the mount has
|
||||
reached a point suitable for testing the filesystem.
|
||||
|
||||
bcachefs is run under valgrind by default, and is checked for errors.
|
||||
'''
|
||||
|
||||
def __init__(self, dev, mnt):
|
||||
self.thread = None
|
||||
self.dev = dev
|
||||
self.mnt = mnt
|
||||
self.ready = threading.Event()
|
||||
self.proc = None
|
||||
self.returncode = None
|
||||
self.stdout = None
|
||||
self.stderr = None
|
||||
self.vout = None
|
||||
|
||||
def run(self):
|
||||
"""Background thread which runs "bcachefs fusemount" under valgrind"""
|
||||
|
||||
vlog = None
|
||||
cmd = []
|
||||
|
||||
if ENABLE_VALGRIND:
|
||||
vlog = tempfile.NamedTemporaryFile()
|
||||
cmd += [ 'valgrind',
|
||||
'--leak-check=full',
|
||||
'--gen-suppressions=all',
|
||||
'--suppressions=valgrind-suppressions.txt',
|
||||
'--log-file={}'.format(vlog.name) ]
|
||||
|
||||
cmd += [ BCH_PATH,
|
||||
'fusemount', '-f', self.dev, self.mnt]
|
||||
|
||||
print("Running {}".format(cmd))
|
||||
|
||||
err = tempfile.TemporaryFile()
|
||||
self.proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=err,
|
||||
encoding='utf-8')
|
||||
|
||||
out1 = self.expect(self.proc.stdout, r'^Fuse mount initialized.$')
|
||||
self.ready.set()
|
||||
|
||||
print("Waiting for process.")
|
||||
(out2, _) = self.proc.communicate()
|
||||
print("Process exited.")
|
||||
|
||||
self.returncode = self.proc.returncode
|
||||
if self.returncode == 0:
|
||||
errors = [ 'btree iterators leaked!',
|
||||
'emergency read only!' ]
|
||||
for e in errors:
|
||||
if e in out2:
|
||||
print('Debug error found in output: "{}"'.format(e))
|
||||
self.returncode = errno.ENOMSG
|
||||
|
||||
self.stdout = out1 + out2
|
||||
self.stderr = err.read()
|
||||
if vlog:
|
||||
self.vout = vlog.read().decode('utf-8')
|
||||
|
||||
def expect(self, pipe, regex):
|
||||
"""Wait for the child process to mount."""
|
||||
|
||||
c = re.compile(regex)
|
||||
|
||||
out = ""
|
||||
for line in pipe:
|
||||
print('Expect line "{}"'.format(line.rstrip()))
|
||||
out += line
|
||||
if c.match(line):
|
||||
print("Matched.")
|
||||
return out
|
||||
|
||||
raise FuseError('stdout did not contain regex "{}"'.format(regex))
|
||||
|
||||
def mount(self):
|
||||
print("Starting fuse thread.")
|
||||
|
||||
assert not self.thread
|
||||
self.thread = threading.Thread(target=self.run)
|
||||
self.thread.start()
|
||||
|
||||
self.ready.wait()
|
||||
print("Fuse is mounted.")
|
||||
|
||||
def unmount(self, timeout=None):
|
||||
print("Unmounting fuse.")
|
||||
run("fusermount3", "-zu", self.mnt)
|
||||
|
||||
if self.thread:
|
||||
print("Waiting for thread to exit.")
|
||||
self.thread.join(timeout)
|
||||
if self.thread.is_alive():
|
||||
if self.proc:
|
||||
self.proc.kill()
|
||||
self.thread.join()
|
||||
else:
|
||||
print("Thread was already done.")
|
||||
|
||||
self.thread = None
|
||||
self.ready.clear()
|
||||
|
||||
if self.vout:
|
||||
check_valgrind(self.vout)
|
||||
|
||||
def verify(self):
|
||||
# avoid throwing exception in assertion
|
||||
assert self.stdout is not None
|
||||
assert self.stderr is not None
|
||||
assert self.returncode == 0
|
||||
assert len(self.stdout) > 0
|
||||
assert len(self.stderr) == 0
|
||||
|
||||
def have_fuse():
|
||||
res = run(BCH_PATH, 'fusemount', valgrind=False)
|
||||
return "Please supply a mountpoint." in res.stdout
|
@ -1,38 +0,0 @@
|
||||
{
|
||||
call_rcu_memb
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible,definite
|
||||
...
|
||||
fun:get_default_call_rcu_data_memb
|
||||
fun:call_rcu_memb
|
||||
}
|
||||
{
|
||||
call_rcu_data_init
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:calloc
|
||||
fun:_dl_allocate_tls
|
||||
...
|
||||
fun:call_rcu_data_init
|
||||
}
|
||||
{
|
||||
urcu_memb_call_rcu
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
...
|
||||
fun:pthread_create*
|
||||
obj:/*/liburcu.so.*
|
||||
...
|
||||
fun:urcu_memb_call_rcu
|
||||
}
|
||||
{
|
||||
pthread_create
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: possible
|
||||
fun:calloc
|
||||
...
|
||||
fun:allocate_stack
|
||||
fun:pthread_create*
|
||||
fun:kthread_create
|
||||
fun:bch2_rebalance_start
|
||||
}
|
Loading…
Reference in New Issue
Block a user