test improvements
This commit is contained in:
parent
e5f4fcaad7
commit
47a580dd77
|
|
@ -3,24 +3,28 @@ import pytest
|
||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# If a test fails, wait a moment before retrieving the captured
|
# If a test fails, wait a moment before retrieving the captured stdout/stderr.
|
||||||
# stdout/stderr. When using a server process, this makes sure that we capture
|
# When using a server process, this makes sure that we capture any potential
|
||||||
# any potential output of the server that comes *after* a test has failed. For
|
# output of the server that comes *after* a test has failed. For example, if a
|
||||||
# example, if a request handler raises an exception, the server first signals an
|
# request handler raises an exception, the server first signals an error to
|
||||||
# error to FUSE (causing the test to fail), and then logs the exception. Without
|
# FUSE (causing the test to fail), and then logs the exception. Without the
|
||||||
# the extra delay, the exception will go into nowhere.
|
# extra delay, the exception will go into nowhere.
|
||||||
@pytest.mark.hookwrapper
|
|
||||||
|
|
||||||
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
def pytest_pyfunc_call(pyfuncitem):
|
def pytest_pyfunc_call(pyfuncitem):
|
||||||
outcome = yield
|
outcome = yield
|
||||||
failed = outcome.excinfo is not None
|
failed = outcome.excinfo is not None
|
||||||
if failed:
|
if failed:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def pass_capfd(request, capfd):
|
def pass_capfd(request, capfd):
|
||||||
'''Provide capfd object to UnitTest instances'''
|
"""Provide capfd object to UnitTest instances"""
|
||||||
request.instance.capfd = capfd
|
request.instance.capfd = capfd
|
||||||
|
|
||||||
|
|
||||||
def check_test_output(capfd):
|
def check_test_output(capfd):
|
||||||
(stdout, stderr) = capfd.readouterr()
|
(stdout, stderr) = capfd.readouterr()
|
||||||
|
|
||||||
|
|
@ -31,39 +35,57 @@ def check_test_output(capfd):
|
||||||
# Strip out false positives
|
# Strip out false positives
|
||||||
for (pattern, flags, count) in capfd.false_positives:
|
for (pattern, flags, count) in capfd.false_positives:
|
||||||
cp = re.compile(pattern, flags)
|
cp = re.compile(pattern, flags)
|
||||||
(stdout, cnt) = cp.subn('', stdout, count=count)
|
(stdout, cnt) = cp.subn("", stdout, count=count)
|
||||||
if count == 0 or count - cnt > 0:
|
if count == 0 or count - cnt > 0:
|
||||||
stderr = cp.sub('', stderr, count=count - cnt)
|
stderr = cp.sub("", stderr, count=count - cnt)
|
||||||
|
|
||||||
patterns = [ r'\b{}\b'.format(x) for x in
|
patterns = [
|
||||||
('exception', 'error', 'warning', 'fatal', 'traceback',
|
r"\b{}\b".format(x)
|
||||||
'fault', 'crash(?:ed)?', 'abort(?:ed)',
|
for x in (
|
||||||
'uninitiali[zs]ed') ]
|
"exception",
|
||||||
patterns += ['^==[0-9]+== ']
|
"error",
|
||||||
|
"warning",
|
||||||
|
"fatal",
|
||||||
|
"traceback",
|
||||||
|
"fault",
|
||||||
|
"crash(?:ed)?",
|
||||||
|
"abort(?:ed)",
|
||||||
|
"uninitiali[zs]ed",
|
||||||
|
)
|
||||||
|
]
|
||||||
|
patterns += ["^==[0-9]+== "]
|
||||||
for pattern in patterns:
|
for pattern in patterns:
|
||||||
cp = re.compile(pattern, re.IGNORECASE | re.MULTILINE)
|
cp = re.compile(pattern, re.IGNORECASE | re.MULTILINE)
|
||||||
hit = cp.search(stderr)
|
hit = cp.search(stderr)
|
||||||
if hit:
|
if hit:
|
||||||
raise AssertionError('Suspicious output to stderr (matched "%s")' % hit.group(0))
|
raise AssertionError(
|
||||||
|
'Suspicious output to stderr (matched "%s")' % hit.group(0)
|
||||||
|
)
|
||||||
hit = cp.search(stdout)
|
hit = cp.search(stdout)
|
||||||
if hit:
|
if hit:
|
||||||
raise AssertionError('Suspicious output to stdout (matched "%s")' % hit.group(0))
|
raise AssertionError(
|
||||||
|
'Suspicious output to stdout (matched "%s")' % hit.group(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def register_output(self, pattern, count=1, flags=re.MULTILINE):
|
def register_output(self, pattern, count=1, flags=re.MULTILINE):
|
||||||
'''Register *pattern* as false positive for output checking
|
"""Register *pattern* as false positive for output checking
|
||||||
|
|
||||||
This prevents the test from failing because the output otherwise
|
This prevents the test from failing because the output otherwise
|
||||||
appears suspicious.
|
appears suspicious.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
self.false_positives.append((pattern, flags, count))
|
self.false_positives.append((pattern, flags, count))
|
||||||
|
|
||||||
|
|
||||||
# This is a terrible hack that allows us to access the fixtures from the
|
# This is a terrible hack that allows us to access the fixtures from the
|
||||||
# pytest_runtest_call hook. Among a lot of other hidden assumptions, it probably
|
# pytest_runtest_call hook. Among a lot of other hidden assumptions, it probably
|
||||||
# relies on tests running sequential (i.e., don't dare to use e.g. the xdist
|
# relies on tests running sequential (i.e., don't dare to use e.g. the xdist
|
||||||
# plugin)
|
# plugin)
|
||||||
current_capfd = None
|
current_capfd = None
|
||||||
@pytest.yield_fixture(autouse=True)
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
def save_cap_fixtures(request, capfd):
|
def save_cap_fixtures(request, capfd):
|
||||||
global current_capfd
|
global current_capfd
|
||||||
capfd.false_positives = []
|
capfd.false_positives = []
|
||||||
|
|
@ -71,7 +93,7 @@ def save_cap_fixtures(request, capfd):
|
||||||
# Monkeypatch in a function to register false positives
|
# Monkeypatch in a function to register false positives
|
||||||
type(capfd).register_output = register_output
|
type(capfd).register_output = register_output
|
||||||
|
|
||||||
if request.config.getoption('capture') == 'no':
|
if request.config.getoption("capture") == "no":
|
||||||
capfd = None
|
capfd = None
|
||||||
current_capfd = capfd
|
current_capfd = capfd
|
||||||
bak = current_capfd
|
bak = current_capfd
|
||||||
|
|
@ -82,6 +104,7 @@ def save_cap_fixtures(request, capfd):
|
||||||
assert bak is current_capfd
|
assert bak is current_capfd
|
||||||
current_capfd = None
|
current_capfd = None
|
||||||
|
|
||||||
|
|
||||||
@pytest.hookimpl(trylast=True)
|
@pytest.hookimpl(trylast=True)
|
||||||
def pytest_runtest_call(item):
|
def pytest_runtest_call(item):
|
||||||
capfd = current_capfd
|
capfd = current_capfd
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,4 @@
|
||||||
[pytest]
|
[pytest]
|
||||||
addopts = --verbose --assert=rewrite --tb=native -x -r a
|
addopts = --verbose --assert=rewrite --tb=native -x -r a
|
||||||
|
|
||||||
|
markers = uses_fuse: Mark to indicate that FUSE is available on the system running the test
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
import pytest
|
import pytest
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.exit(pytest.main([__file__] + sys.argv[1:]))
|
sys.exit(pytest.main([__file__] + sys.argv[1:]))
|
||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
@ -13,31 +14,60 @@ import stat
|
||||||
import shutil
|
import shutil
|
||||||
import filecmp
|
import filecmp
|
||||||
import errno
|
import errno
|
||||||
from contextlib import contextmanager
|
|
||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from util import (wait_for_mount, umount, cleanup, base_cmdline,
|
from util import (
|
||||||
basename, fuse_test_marker, safe_sleep)
|
wait_for_mount,
|
||||||
|
umount,
|
||||||
|
cleanup,
|
||||||
|
base_cmdline,
|
||||||
|
basename,
|
||||||
|
fuse_test_marker,
|
||||||
|
safe_sleep,
|
||||||
|
os_create,
|
||||||
|
os_open,
|
||||||
|
)
|
||||||
from os.path import join as pjoin
|
from os.path import join as pjoin
|
||||||
|
|
||||||
TEST_FILE = __file__
|
TEST_FILE = __file__
|
||||||
|
|
||||||
pytestmark = fuse_test_marker()
|
pytestmark = fuse_test_marker()
|
||||||
|
|
||||||
with open(TEST_FILE, 'rb') as fh:
|
with open(TEST_FILE, "rb") as fh:
|
||||||
TEST_DATA = fh.read()
|
TEST_DATA = fh.read()
|
||||||
|
|
||||||
def name_generator(__ctr=[0]):
|
|
||||||
__ctr[0] += 1
|
|
||||||
return 'testfile_%d' % __ctr[0]
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("debug", (False, True))
|
def name_generator(__ctr=[0]) -> str:
|
||||||
@pytest.mark.parametrize("cache_timeout", (0,1))
|
"""Generate a fresh filename on each call"""
|
||||||
@pytest.mark.parametrize("sync_rd", (True, False))
|
|
||||||
@pytest.mark.parametrize("multiconn", (True,False))
|
__ctr[0] += 1
|
||||||
def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, multiconn, capfd):
|
return f"testfile_{__ctr[0]}"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"debug",
|
||||||
|
[pytest.param(False, id="debug=false"), pytest.param(True, id="debug=true")],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"cache_timeout",
|
||||||
|
[pytest.param(0, id="cache_timeout=0"), pytest.param(1, id="cache_timeout=1")],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"sync_rd",
|
||||||
|
[pytest.param(True, id="sync_rd=true"), pytest.param(False, id="sync_rd=false")],
|
||||||
|
)
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"multiconn",
|
||||||
|
[
|
||||||
|
pytest.param(True, id="multiconn=true"),
|
||||||
|
pytest.param(False, id="multiconn=false"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_sshfs(
|
||||||
|
tmpdir, debug: bool, cache_timeout: int, sync_rd: bool, multiconn: bool, capfd
|
||||||
|
) -> None:
|
||||||
|
|
||||||
# Avoid false positives from debug messages
|
# Avoid false positives from debug messages
|
||||||
#if debug:
|
# if debug:
|
||||||
# capfd.register_output(r'^ unique: [0-9]+, error: -[0-9]+ .+$',
|
# capfd.register_output(r'^ unique: [0-9]+, error: -[0-9]+ .+$',
|
||||||
# count=0)
|
# count=0)
|
||||||
|
|
||||||
|
|
@ -46,45 +76,60 @@ def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, multiconn, capfd):
|
||||||
|
|
||||||
# Test if we can ssh into localhost without password
|
# Test if we can ssh into localhost without password
|
||||||
try:
|
try:
|
||||||
res = subprocess.call(['ssh', '-o', 'KbdInteractiveAuthentication=no',
|
res = subprocess.call(
|
||||||
'-o', 'ChallengeResponseAuthentication=no',
|
[
|
||||||
'-o', 'PasswordAuthentication=no',
|
"ssh",
|
||||||
'localhost', '--', 'true'], stdin=subprocess.DEVNULL,
|
"-o",
|
||||||
timeout=10)
|
"StrictHostKeyChecking=no",
|
||||||
|
"-o",
|
||||||
|
"KbdInteractiveAuthentication=no",
|
||||||
|
"-o",
|
||||||
|
"ChallengeResponseAuthentication=no",
|
||||||
|
"-o",
|
||||||
|
"PasswordAuthentication=no",
|
||||||
|
"localhost",
|
||||||
|
"--",
|
||||||
|
"true",
|
||||||
|
],
|
||||||
|
stdin=subprocess.DEVNULL,
|
||||||
|
timeout=10,
|
||||||
|
)
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
res = 1
|
res = 1
|
||||||
if res != 0:
|
if res != 0:
|
||||||
pytest.fail('Unable to ssh into localhost without password prompt.')
|
pytest.fail("Unable to ssh into localhost without password prompt.")
|
||||||
|
|
||||||
mnt_dir = str(tmpdir.mkdir('mnt'))
|
mnt_dir = str(tmpdir.mkdir("mnt"))
|
||||||
src_dir = str(tmpdir.mkdir('src'))
|
src_dir = str(tmpdir.mkdir("src"))
|
||||||
|
|
||||||
cmdline = base_cmdline + [ pjoin(basename, 'sshfs'),
|
cmdline = base_cmdline + [
|
||||||
'-f', 'localhost:' + src_dir, mnt_dir ]
|
pjoin(basename, "sshfs"),
|
||||||
|
"-f",
|
||||||
|
f"localhost:{src_dir}",
|
||||||
|
mnt_dir,
|
||||||
|
]
|
||||||
if debug:
|
if debug:
|
||||||
cmdline += [ '-o', 'sshfs_debug' ]
|
cmdline += ["-o", "sshfs_debug"]
|
||||||
|
|
||||||
if sync_rd:
|
if sync_rd:
|
||||||
cmdline += [ '-o', 'sync_readdir' ]
|
cmdline += ["-o", "sync_readdir"]
|
||||||
|
|
||||||
# SSHFS Cache
|
# SSHFS Cache
|
||||||
if cache_timeout == 0:
|
if cache_timeout == 0:
|
||||||
cmdline += [ '-o', 'dir_cache=no' ]
|
cmdline += ["-o", "dir_cache=no"]
|
||||||
else:
|
else:
|
||||||
cmdline += [ '-o', 'dcache_timeout=%d' % cache_timeout,
|
cmdline += ["-o", f"dcache_timeout={cache_timeout}", "-o", "dir_cache=yes"]
|
||||||
'-o', 'dir_cache=yes' ]
|
|
||||||
|
|
||||||
# FUSE Cache
|
# FUSE Cache
|
||||||
cmdline += [ '-o', 'entry_timeout=0',
|
cmdline += ["-o", "entry_timeout=0", "-o", "attr_timeout=0"]
|
||||||
'-o', 'attr_timeout=0' ]
|
|
||||||
|
|
||||||
if multiconn:
|
if multiconn:
|
||||||
cmdline += [ '-o', 'max_conns=3' ]
|
cmdline += ["-o", "max_conns=3"]
|
||||||
|
|
||||||
new_env = dict(os.environ) # copy, don't modify
|
new_env = dict(os.environ) # copy, don't modify
|
||||||
|
|
||||||
# Abort on warnings from glib
|
# Abort on warnings from glib
|
||||||
new_env['G_DEBUG'] = 'fatal-warnings'
|
new_env["G_DEBUG"] = "fatal-warnings"
|
||||||
|
|
||||||
mount_process = subprocess.Popen(cmdline, env=new_env)
|
mount_process = subprocess.Popen(cmdline, env=new_env)
|
||||||
try:
|
try:
|
||||||
|
|
@ -114,30 +159,20 @@ def test_sshfs(tmpdir, debug, cache_timeout, sync_rd, multiconn, capfd):
|
||||||
tst_truncate_path(mnt_dir)
|
tst_truncate_path(mnt_dir)
|
||||||
tst_truncate_fd(mnt_dir)
|
tst_truncate_fd(mnt_dir)
|
||||||
tst_open_unlink(mnt_dir)
|
tst_open_unlink(mnt_dir)
|
||||||
except:
|
except Exception as exc:
|
||||||
cleanup(mount_process, mnt_dir)
|
cleanup(mount_process, mnt_dir)
|
||||||
raise
|
raise exc
|
||||||
else:
|
else:
|
||||||
umount(mount_process, mnt_dir)
|
umount(mount_process, mnt_dir)
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def os_open(name, flags):
|
|
||||||
fd = os.open(name, flags)
|
|
||||||
try:
|
|
||||||
yield fd
|
|
||||||
finally:
|
|
||||||
os.close(fd)
|
|
||||||
|
|
||||||
def os_create(name):
|
|
||||||
os.close(os.open(name, os.O_CREAT | os.O_RDWR))
|
|
||||||
|
|
||||||
def tst_unlink(src_dir, mnt_dir, cache_timeout):
|
def tst_unlink(src_dir, mnt_dir, cache_timeout):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
fullname = mnt_dir + "/" + name
|
fullname = mnt_dir + "/" + name
|
||||||
with open(pjoin(src_dir, name), 'wb') as fh:
|
with open(pjoin(src_dir, name), "wb") as fh:
|
||||||
fh.write(b'hello')
|
fh.write(b"hello")
|
||||||
if cache_timeout:
|
if cache_timeout:
|
||||||
safe_sleep(cache_timeout+1)
|
safe_sleep(cache_timeout + 1)
|
||||||
assert name in os.listdir(mnt_dir)
|
assert name in os.listdir(mnt_dir)
|
||||||
os.unlink(fullname)
|
os.unlink(fullname)
|
||||||
with pytest.raises(OSError) as exc_info:
|
with pytest.raises(OSError) as exc_info:
|
||||||
|
|
@ -146,22 +181,24 @@ def tst_unlink(src_dir, mnt_dir, cache_timeout):
|
||||||
assert name not in os.listdir(mnt_dir)
|
assert name not in os.listdir(mnt_dir)
|
||||||
assert name not in os.listdir(src_dir)
|
assert name not in os.listdir(src_dir)
|
||||||
|
|
||||||
|
|
||||||
def tst_mkdir(mnt_dir):
|
def tst_mkdir(mnt_dir):
|
||||||
dirname = name_generator()
|
dirname = name_generator()
|
||||||
fullname = mnt_dir + "/" + dirname
|
fullname = mnt_dir + "/" + dirname
|
||||||
os.mkdir(fullname)
|
os.mkdir(fullname)
|
||||||
fstat = os.stat(fullname)
|
fstat = os.stat(fullname)
|
||||||
assert stat.S_ISDIR(fstat.st_mode)
|
assert stat.S_ISDIR(fstat.st_mode)
|
||||||
assert os.listdir(fullname) == []
|
assert os.listdir(fullname) == []
|
||||||
assert fstat.st_nlink in (1,2)
|
assert fstat.st_nlink in (1, 2)
|
||||||
assert dirname in os.listdir(mnt_dir)
|
assert dirname in os.listdir(mnt_dir)
|
||||||
|
|
||||||
|
|
||||||
def tst_rmdir(src_dir, mnt_dir, cache_timeout):
|
def tst_rmdir(src_dir, mnt_dir, cache_timeout):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
fullname = mnt_dir + "/" + name
|
fullname = mnt_dir + "/" + name
|
||||||
os.mkdir(pjoin(src_dir, name))
|
os.mkdir(pjoin(src_dir, name))
|
||||||
if cache_timeout:
|
if cache_timeout:
|
||||||
safe_sleep(cache_timeout+1)
|
safe_sleep(cache_timeout + 1)
|
||||||
assert name in os.listdir(mnt_dir)
|
assert name in os.listdir(mnt_dir)
|
||||||
os.rmdir(fullname)
|
os.rmdir(fullname)
|
||||||
with pytest.raises(OSError) as exc_info:
|
with pytest.raises(OSError) as exc_info:
|
||||||
|
|
@ -170,6 +207,7 @@ def tst_rmdir(src_dir, mnt_dir, cache_timeout):
|
||||||
assert name not in os.listdir(mnt_dir)
|
assert name not in os.listdir(mnt_dir)
|
||||||
assert name not in os.listdir(src_dir)
|
assert name not in os.listdir(src_dir)
|
||||||
|
|
||||||
|
|
||||||
def tst_symlink(mnt_dir):
|
def tst_symlink(mnt_dir):
|
||||||
linkname = name_generator()
|
linkname = name_generator()
|
||||||
fullname = mnt_dir + "/" + linkname
|
fullname = mnt_dir + "/" + linkname
|
||||||
|
|
@ -180,6 +218,7 @@ def tst_symlink(mnt_dir):
|
||||||
assert fstat.st_nlink == 1
|
assert fstat.st_nlink == 1
|
||||||
assert linkname in os.listdir(mnt_dir)
|
assert linkname in os.listdir(mnt_dir)
|
||||||
|
|
||||||
|
|
||||||
def tst_create(mnt_dir):
|
def tst_create(mnt_dir):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
fullname = pjoin(mnt_dir, name)
|
fullname = pjoin(mnt_dir, name)
|
||||||
|
|
@ -197,6 +236,7 @@ def tst_create(mnt_dir):
|
||||||
assert fstat.st_nlink == 1
|
assert fstat.st_nlink == 1
|
||||||
assert fstat.st_size == 0
|
assert fstat.st_size == 0
|
||||||
|
|
||||||
|
|
||||||
def tst_chown(mnt_dir):
|
def tst_chown(mnt_dir):
|
||||||
filename = pjoin(mnt_dir, name_generator())
|
filename = pjoin(mnt_dir, name_generator())
|
||||||
os.mkdir(filename)
|
os.mkdir(filename)
|
||||||
|
|
@ -216,37 +256,38 @@ def tst_chown(mnt_dir):
|
||||||
assert fstat.st_uid == uid_new
|
assert fstat.st_uid == uid_new
|
||||||
assert fstat.st_gid == gid_new
|
assert fstat.st_gid == gid_new
|
||||||
|
|
||||||
|
|
||||||
def tst_open_read(src_dir, mnt_dir):
|
def tst_open_read(src_dir, mnt_dir):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
with open(pjoin(src_dir, name), 'wb') as fh_out, \
|
with open(pjoin(src_dir, name), "wb") as fh_out, open(TEST_FILE, "rb") as fh_in:
|
||||||
open(TEST_FILE, 'rb') as fh_in:
|
|
||||||
shutil.copyfileobj(fh_in, fh_out)
|
shutil.copyfileobj(fh_in, fh_out)
|
||||||
|
|
||||||
assert filecmp.cmp(pjoin(mnt_dir, name), TEST_FILE, False)
|
assert filecmp.cmp(pjoin(mnt_dir, name), TEST_FILE, False)
|
||||||
|
|
||||||
|
|
||||||
def tst_open_write(src_dir, mnt_dir):
|
def tst_open_write(src_dir, mnt_dir):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
fd = os.open(pjoin(src_dir, name),
|
fd = os.open(pjoin(src_dir, name), os.O_CREAT | os.O_RDWR)
|
||||||
os.O_CREAT | os.O_RDWR)
|
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
fullname = pjoin(mnt_dir, name)
|
fullname = pjoin(mnt_dir, name)
|
||||||
with open(fullname, 'wb') as fh_out, \
|
with open(fullname, "wb") as fh_out, open(TEST_FILE, "rb") as fh_in:
|
||||||
open(TEST_FILE, 'rb') as fh_in:
|
|
||||||
shutil.copyfileobj(fh_in, fh_out)
|
shutil.copyfileobj(fh_in, fh_out)
|
||||||
|
|
||||||
assert filecmp.cmp(fullname, TEST_FILE, False)
|
assert filecmp.cmp(fullname, TEST_FILE, False)
|
||||||
|
|
||||||
|
|
||||||
def tst_append(src_dir, mnt_dir):
|
def tst_append(src_dir, mnt_dir):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
os_create(pjoin(src_dir, name))
|
os_create(pjoin(src_dir, name))
|
||||||
fullname = pjoin(mnt_dir, name)
|
fullname = pjoin(mnt_dir, name)
|
||||||
with os_open(fullname, os.O_WRONLY) as fd:
|
with os_open(fullname, os.O_WRONLY) as fd:
|
||||||
os.write(fd, b'foo\n')
|
os.write(fd, b"foo\n")
|
||||||
with os_open(fullname, os.O_WRONLY|os.O_APPEND) as fd:
|
with os_open(fullname, os.O_WRONLY | os.O_APPEND) as fd:
|
||||||
os.write(fd, b'bar\n')
|
os.write(fd, b"bar\n")
|
||||||
|
|
||||||
|
with open(fullname, "rb") as fh:
|
||||||
|
assert fh.read() == b"foo\nbar\n"
|
||||||
|
|
||||||
with open(fullname, 'rb') as fh:
|
|
||||||
assert fh.read() == b'foo\nbar\n'
|
|
||||||
|
|
||||||
def tst_seek(src_dir, mnt_dir):
|
def tst_seek(src_dir, mnt_dir):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
|
|
@ -254,20 +295,21 @@ def tst_seek(src_dir, mnt_dir):
|
||||||
fullname = pjoin(mnt_dir, name)
|
fullname = pjoin(mnt_dir, name)
|
||||||
with os_open(fullname, os.O_WRONLY) as fd:
|
with os_open(fullname, os.O_WRONLY) as fd:
|
||||||
os.lseek(fd, 1, os.SEEK_SET)
|
os.lseek(fd, 1, os.SEEK_SET)
|
||||||
os.write(fd, b'foobar\n')
|
os.write(fd, b"foobar\n")
|
||||||
with os_open(fullname, os.O_WRONLY) as fd:
|
with os_open(fullname, os.O_WRONLY) as fd:
|
||||||
os.lseek(fd, 4, os.SEEK_SET)
|
os.lseek(fd, 4, os.SEEK_SET)
|
||||||
os.write(fd, b'com')
|
os.write(fd, b"com")
|
||||||
|
|
||||||
|
with open(fullname, "rb") as fh:
|
||||||
|
assert fh.read() == b"\0foocom\n"
|
||||||
|
|
||||||
with open(fullname, 'rb') as fh:
|
|
||||||
assert fh.read() == b'\0foocom\n'
|
|
||||||
|
|
||||||
def tst_open_unlink(mnt_dir):
|
def tst_open_unlink(mnt_dir):
|
||||||
name = pjoin(mnt_dir, name_generator())
|
name = pjoin(mnt_dir, name_generator())
|
||||||
data1 = b'foo'
|
data1 = b"foo"
|
||||||
data2 = b'bar'
|
data2 = b"bar"
|
||||||
fullname = pjoin(mnt_dir, name)
|
fullname = pjoin(mnt_dir, name)
|
||||||
with open(fullname, 'wb+', buffering=0) as fh:
|
with open(fullname, "wb+", buffering=0) as fh:
|
||||||
fh.write(data1)
|
fh.write(data1)
|
||||||
os.unlink(fullname)
|
os.unlink(fullname)
|
||||||
with pytest.raises(OSError) as exc_info:
|
with pytest.raises(OSError) as exc_info:
|
||||||
|
|
@ -276,11 +318,13 @@ def tst_open_unlink(mnt_dir):
|
||||||
assert name not in os.listdir(mnt_dir)
|
assert name not in os.listdir(mnt_dir)
|
||||||
fh.write(data2)
|
fh.write(data2)
|
||||||
fh.seek(0)
|
fh.seek(0)
|
||||||
assert fh.read() == data1+data2
|
assert fh.read() == data1 + data2
|
||||||
|
|
||||||
|
|
||||||
def tst_statvfs(mnt_dir):
|
def tst_statvfs(mnt_dir):
|
||||||
os.statvfs(mnt_dir)
|
os.statvfs(mnt_dir)
|
||||||
|
|
||||||
|
|
||||||
def tst_link(mnt_dir, cache_timeout):
|
def tst_link(mnt_dir, cache_timeout):
|
||||||
name1 = pjoin(mnt_dir, name_generator())
|
name1 = pjoin(mnt_dir, name_generator())
|
||||||
name2 = pjoin(mnt_dir, name_generator())
|
name2 = pjoin(mnt_dir, name_generator())
|
||||||
|
|
@ -302,8 +346,16 @@ def tst_link(mnt_dir, cache_timeout):
|
||||||
|
|
||||||
fstat1 = os.lstat(name1)
|
fstat1 = os.lstat(name1)
|
||||||
fstat2 = os.lstat(name2)
|
fstat2 = os.lstat(name2)
|
||||||
for attr in ('st_mode', 'st_dev', 'st_uid', 'st_gid',
|
for attr in (
|
||||||
'st_size', 'st_atime', 'st_mtime', 'st_ctime'):
|
"st_mode",
|
||||||
|
"st_dev",
|
||||||
|
"st_uid",
|
||||||
|
"st_gid",
|
||||||
|
"st_size",
|
||||||
|
"st_atime",
|
||||||
|
"st_mtime",
|
||||||
|
"st_ctime",
|
||||||
|
):
|
||||||
assert getattr(fstat1, attr) == getattr(fstat2, attr)
|
assert getattr(fstat1, attr) == getattr(fstat2, attr)
|
||||||
assert os.path.basename(name2) in os.listdir(mnt_dir)
|
assert os.path.basename(name2) in os.listdir(mnt_dir)
|
||||||
assert filecmp.cmp(name1, name2, False)
|
assert filecmp.cmp(name1, name2, False)
|
||||||
|
|
@ -316,6 +368,7 @@ def tst_link(mnt_dir, cache_timeout):
|
||||||
|
|
||||||
os.unlink(name1)
|
os.unlink(name1)
|
||||||
|
|
||||||
|
|
||||||
def tst_readdir(src_dir, mnt_dir):
|
def tst_readdir(src_dir, mnt_dir):
|
||||||
newdir = name_generator()
|
newdir = name_generator()
|
||||||
src_newdir = pjoin(src_dir, newdir)
|
src_newdir = pjoin(src_dir, newdir)
|
||||||
|
|
@ -331,7 +384,7 @@ def tst_readdir(src_dir, mnt_dir):
|
||||||
|
|
||||||
listdir_is = os.listdir(mnt_newdir)
|
listdir_is = os.listdir(mnt_newdir)
|
||||||
listdir_is.sort()
|
listdir_is.sort()
|
||||||
listdir_should = [ os.path.basename(file_), os.path.basename(subdir) ]
|
listdir_should = [os.path.basename(file_), os.path.basename(subdir)]
|
||||||
listdir_should.sort()
|
listdir_should.sort()
|
||||||
assert listdir_is == listdir_should
|
assert listdir_is == listdir_should
|
||||||
|
|
||||||
|
|
@ -340,11 +393,12 @@ def tst_readdir(src_dir, mnt_dir):
|
||||||
os.rmdir(subdir)
|
os.rmdir(subdir)
|
||||||
os.rmdir(src_newdir)
|
os.rmdir(src_newdir)
|
||||||
|
|
||||||
|
|
||||||
def tst_truncate_path(mnt_dir):
|
def tst_truncate_path(mnt_dir):
|
||||||
assert len(TEST_DATA) > 1024
|
assert len(TEST_DATA) > 1024
|
||||||
|
|
||||||
filename = pjoin(mnt_dir, name_generator())
|
filename = pjoin(mnt_dir, name_generator())
|
||||||
with open(filename, 'wb') as fh:
|
with open(filename, "wb") as fh:
|
||||||
fh.write(TEST_DATA)
|
fh.write(TEST_DATA)
|
||||||
|
|
||||||
fstat = os.stat(filename)
|
fstat = os.stat(filename)
|
||||||
|
|
@ -354,21 +408,22 @@ def tst_truncate_path(mnt_dir):
|
||||||
# Add zeros at the end
|
# Add zeros at the end
|
||||||
os.truncate(filename, size + 1024)
|
os.truncate(filename, size + 1024)
|
||||||
assert os.stat(filename).st_size == size + 1024
|
assert os.stat(filename).st_size == size + 1024
|
||||||
with open(filename, 'rb') as fh:
|
with open(filename, "rb") as fh:
|
||||||
assert fh.read(size) == TEST_DATA
|
assert fh.read(size) == TEST_DATA
|
||||||
assert fh.read(1025) == b'\0' * 1024
|
assert fh.read(1025) == b"\0" * 1024
|
||||||
|
|
||||||
# Truncate data
|
# Truncate data
|
||||||
os.truncate(filename, size - 1024)
|
os.truncate(filename, size - 1024)
|
||||||
assert os.stat(filename).st_size == size - 1024
|
assert os.stat(filename).st_size == size - 1024
|
||||||
with open(filename, 'rb') as fh:
|
with open(filename, "rb") as fh:
|
||||||
assert fh.read(size) == TEST_DATA[:size-1024]
|
assert fh.read(size) == TEST_DATA[: size - 1024]
|
||||||
|
|
||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
|
|
||||||
|
|
||||||
def tst_truncate_fd(mnt_dir):
|
def tst_truncate_fd(mnt_dir):
|
||||||
assert len(TEST_DATA) > 1024
|
assert len(TEST_DATA) > 1024
|
||||||
with NamedTemporaryFile('w+b', 0, dir=mnt_dir) as fh:
|
with NamedTemporaryFile("w+b", 0, dir=mnt_dir) as fh:
|
||||||
fd = fh.fileno()
|
fd = fh.fileno()
|
||||||
fh.write(TEST_DATA)
|
fh.write(TEST_DATA)
|
||||||
fstat = os.fstat(fd)
|
fstat = os.fstat(fd)
|
||||||
|
|
@ -380,13 +435,14 @@ def tst_truncate_fd(mnt_dir):
|
||||||
assert os.fstat(fd).st_size == size + 1024
|
assert os.fstat(fd).st_size == size + 1024
|
||||||
fh.seek(0)
|
fh.seek(0)
|
||||||
assert fh.read(size) == TEST_DATA
|
assert fh.read(size) == TEST_DATA
|
||||||
assert fh.read(1025) == b'\0' * 1024
|
assert fh.read(1025) == b"\0" * 1024
|
||||||
|
|
||||||
# Truncate data
|
# Truncate data
|
||||||
os.ftruncate(fd, size - 1024)
|
os.ftruncate(fd, size - 1024)
|
||||||
assert os.fstat(fd).st_size == size - 1024
|
assert os.fstat(fd).st_size == size - 1024
|
||||||
fh.seek(0)
|
fh.seek(0)
|
||||||
assert fh.read(size) == TEST_DATA[:size-1024]
|
assert fh.read(size) == TEST_DATA[: size - 1024]
|
||||||
|
|
||||||
|
|
||||||
def tst_utimens(mnt_dir, tol=0):
|
def tst_utimens(mnt_dir, tol=0):
|
||||||
filename = pjoin(mnt_dir, name_generator())
|
filename = pjoin(mnt_dir, name_generator())
|
||||||
|
|
@ -395,20 +451,21 @@ def tst_utimens(mnt_dir, tol=0):
|
||||||
|
|
||||||
atime = fstat.st_atime + 42.28
|
atime = fstat.st_atime + 42.28
|
||||||
mtime = fstat.st_mtime - 42.23
|
mtime = fstat.st_mtime - 42.23
|
||||||
if sys.version_info < (3,3):
|
if sys.version_info < (3, 3):
|
||||||
os.utime(filename, (atime, mtime))
|
os.utime(filename, (atime, mtime))
|
||||||
else:
|
else:
|
||||||
atime_ns = fstat.st_atime_ns + int(42.28*1e9)
|
atime_ns = fstat.st_atime_ns + int(42.28 * 1e9)
|
||||||
mtime_ns = fstat.st_mtime_ns - int(42.23*1e9)
|
mtime_ns = fstat.st_mtime_ns - int(42.23 * 1e9)
|
||||||
os.utime(filename, None, ns=(atime_ns, mtime_ns))
|
os.utime(filename, None, ns=(atime_ns, mtime_ns))
|
||||||
|
|
||||||
fstat = os.lstat(filename)
|
fstat = os.lstat(filename)
|
||||||
|
|
||||||
assert abs(fstat.st_atime - atime) < tol
|
assert abs(fstat.st_atime - atime) < tol
|
||||||
assert abs(fstat.st_mtime - mtime) < tol
|
assert abs(fstat.st_mtime - mtime) < tol
|
||||||
if sys.version_info >= (3,3):
|
if sys.version_info >= (3, 3):
|
||||||
assert abs(fstat.st_atime_ns - atime_ns) < tol*1e9
|
assert abs(fstat.st_atime_ns - atime_ns) < tol * 1e9
|
||||||
assert abs(fstat.st_mtime_ns - mtime_ns) < tol*1e9
|
assert abs(fstat.st_mtime_ns - mtime_ns) < tol * 1e9
|
||||||
|
|
||||||
|
|
||||||
def tst_utimens_now(mnt_dir):
|
def tst_utimens_now(mnt_dir):
|
||||||
fullname = pjoin(mnt_dir, name_generator())
|
fullname = pjoin(mnt_dir, name_generator())
|
||||||
|
|
@ -422,17 +479,18 @@ def tst_utimens_now(mnt_dir):
|
||||||
assert fstat.st_atime != 0
|
assert fstat.st_atime != 0
|
||||||
assert fstat.st_mtime != 0
|
assert fstat.st_mtime != 0
|
||||||
|
|
||||||
|
|
||||||
def tst_passthrough(src_dir, mnt_dir, cache_timeout):
|
def tst_passthrough(src_dir, mnt_dir, cache_timeout):
|
||||||
name = name_generator()
|
name = name_generator()
|
||||||
src_name = pjoin(src_dir, name)
|
src_name = pjoin(src_dir, name)
|
||||||
mnt_name = pjoin(src_dir, name)
|
mnt_name = pjoin(src_dir, name)
|
||||||
assert name not in os.listdir(src_dir)
|
assert name not in os.listdir(src_dir)
|
||||||
assert name not in os.listdir(mnt_dir)
|
assert name not in os.listdir(mnt_dir)
|
||||||
with open(src_name, 'w') as fh:
|
with open(src_name, "w") as fh:
|
||||||
fh.write('Hello, world')
|
fh.write("Hello, world")
|
||||||
assert name in os.listdir(src_dir)
|
assert name in os.listdir(src_dir)
|
||||||
if cache_timeout:
|
if cache_timeout:
|
||||||
safe_sleep(cache_timeout+1)
|
safe_sleep(cache_timeout + 1)
|
||||||
assert name in os.listdir(mnt_dir)
|
assert name in os.listdir(mnt_dir)
|
||||||
assert os.stat(src_name) == os.stat(mnt_name)
|
assert os.stat(src_name) == os.stat(mnt_name)
|
||||||
|
|
||||||
|
|
@ -441,10 +499,10 @@ def tst_passthrough(src_dir, mnt_dir, cache_timeout):
|
||||||
mnt_name = pjoin(src_dir, name)
|
mnt_name = pjoin(src_dir, name)
|
||||||
assert name not in os.listdir(src_dir)
|
assert name not in os.listdir(src_dir)
|
||||||
assert name not in os.listdir(mnt_dir)
|
assert name not in os.listdir(mnt_dir)
|
||||||
with open(mnt_name, 'w') as fh:
|
with open(mnt_name, "w") as fh:
|
||||||
fh.write('Hello, world')
|
fh.write("Hello, world")
|
||||||
assert name in os.listdir(src_dir)
|
assert name in os.listdir(src_dir)
|
||||||
if cache_timeout:
|
if cache_timeout:
|
||||||
safe_sleep(cache_timeout+1)
|
safe_sleep(cache_timeout + 1)
|
||||||
assert name in os.listdir(mnt_dir)
|
assert name in os.listdir(mnt_dir)
|
||||||
assert os.stat(src_name) == os.stat(mnt_name)
|
assert os.stat(src_name) == os.stat(mnt_name)
|
||||||
|
|
|
||||||
73
test/util.py
73
test/util.py
|
|
@ -5,25 +5,42 @@ import os
|
||||||
import stat
|
import stat
|
||||||
import time
|
import time
|
||||||
from os.path import join as pjoin
|
from os.path import join as pjoin
|
||||||
|
from contextlib import contextmanager
|
||||||
|
|
||||||
basename = pjoin(os.path.dirname(__file__), '..')
|
basename = pjoin(os.path.dirname(__file__), "..")
|
||||||
|
|
||||||
def wait_for_mount(mount_process, mnt_dir,
|
|
||||||
test_fn=os.path.ismount):
|
def os_create(name):
|
||||||
|
os.close(os.open(name, os.O_CREAT | os.O_RDWR))
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def os_open(name, flags):
|
||||||
|
fd = os.open(name, flags)
|
||||||
|
try:
|
||||||
|
yield fd
|
||||||
|
finally:
|
||||||
|
os.close(fd)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_mount(mount_process, mnt_dir, test_fn=os.path.ismount):
|
||||||
elapsed = 0
|
elapsed = 0
|
||||||
while elapsed < 30:
|
while elapsed < 30:
|
||||||
if test_fn(mnt_dir):
|
if test_fn(mnt_dir):
|
||||||
return True
|
return True
|
||||||
if mount_process.poll() is not None:
|
if mount_process.poll() is not None:
|
||||||
pytest.fail('file system process terminated prematurely')
|
pytest.fail("file system process terminated prematurely")
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
elapsed += 0.1
|
elapsed += 0.1
|
||||||
pytest.fail("mountpoint failed to come up")
|
pytest.fail("mountpoint failed to come up")
|
||||||
|
|
||||||
|
|
||||||
def cleanup(mount_process, mnt_dir):
|
def cleanup(mount_process, mnt_dir):
|
||||||
subprocess.call(['fusermount', '-z', '-u', mnt_dir],
|
subprocess.call(
|
||||||
stdout=subprocess.DEVNULL,
|
["fusermount", "-z", "-u", mnt_dir],
|
||||||
stderr=subprocess.STDOUT)
|
stdout=subprocess.DEVNULL,
|
||||||
|
stderr=subprocess.STDOUT,
|
||||||
|
)
|
||||||
mount_process.terminate()
|
mount_process.terminate()
|
||||||
try:
|
try:
|
||||||
mount_process.wait(1)
|
mount_process.wait(1)
|
||||||
|
|
@ -32,7 +49,7 @@ def cleanup(mount_process, mnt_dir):
|
||||||
|
|
||||||
|
|
||||||
def umount(mount_process, mnt_dir):
|
def umount(mount_process, mnt_dir):
|
||||||
subprocess.check_call(['fusermount3', '-z', '-u', mnt_dir ])
|
subprocess.check_call(["fusermount3", "-z", "-u", mnt_dir])
|
||||||
assert not os.path.ismount(mnt_dir)
|
assert not os.path.ismount(mnt_dir)
|
||||||
|
|
||||||
# Give mount process a little while to terminate. Popen.wait(timeout)
|
# Give mount process a little while to terminate. Popen.wait(timeout)
|
||||||
|
|
@ -43,18 +60,19 @@ def umount(mount_process, mnt_dir):
|
||||||
if code is not None:
|
if code is not None:
|
||||||
if code == 0:
|
if code == 0:
|
||||||
return
|
return
|
||||||
pytest.fail('file system process terminated with code %s' % (code,))
|
pytest.fail(f"file system process terminated with code {code}")
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
elapsed += 0.1
|
elapsed += 0.1
|
||||||
pytest.fail('mount process did not terminate')
|
pytest.fail("mount process did not terminate")
|
||||||
|
|
||||||
|
|
||||||
def safe_sleep(secs):
|
def safe_sleep(secs):
|
||||||
'''Like time.sleep(), but sleep for at least *secs*
|
"""Like time.sleep(), but sleep for at least *secs*
|
||||||
|
|
||||||
`time.sleep` may sleep less than the given period if a signal is
|
`time.sleep` may sleep less than the given period if a signal is
|
||||||
received. This function ensures that we sleep for at least the
|
received. This function ensures that we sleep for at least the
|
||||||
desired time.
|
desired time.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
end = now + secs
|
end = now + secs
|
||||||
|
|
@ -62,24 +80,27 @@ def safe_sleep(secs):
|
||||||
time.sleep(end - now)
|
time.sleep(end - now)
|
||||||
now = time.time()
|
now = time.time()
|
||||||
|
|
||||||
|
|
||||||
def fuse_test_marker():
|
def fuse_test_marker():
|
||||||
'''Return a pytest.marker that indicates FUSE availability
|
"""Return a pytest.marker that indicates FUSE availability
|
||||||
|
|
||||||
If system/user/environment does not support FUSE, return
|
If system/user/environment does not support FUSE, return
|
||||||
a `pytest.mark.skip` object with more details. If FUSE is
|
a `pytest.mark.skip` object with more details. If FUSE is
|
||||||
supported, return `pytest.mark.uses_fuse()`.
|
supported, return `pytest.mark.uses_fuse()`.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
skip = lambda x: pytest.mark.skip(reason=x)
|
def skip(reason: str):
|
||||||
|
return pytest.mark.skip(reason=reason)
|
||||||
|
|
||||||
with subprocess.Popen(['which', 'fusermount'], stdout=subprocess.PIPE,
|
with subprocess.Popen(
|
||||||
universal_newlines=True) as which:
|
["which", "fusermount"], stdout=subprocess.PIPE, universal_newlines=True
|
||||||
|
) as which:
|
||||||
fusermount_path = which.communicate()[0].strip()
|
fusermount_path = which.communicate()[0].strip()
|
||||||
|
|
||||||
if not fusermount_path or which.returncode != 0:
|
if not fusermount_path or which.returncode != 0:
|
||||||
return skip("Can't find fusermount executable")
|
return skip("Can't find fusermount executable")
|
||||||
|
|
||||||
if not os.path.exists('/dev/fuse'):
|
if not os.path.exists("/dev/fuse"):
|
||||||
return skip("FUSE kernel module does not seem to be loaded")
|
return skip("FUSE kernel module does not seem to be loaded")
|
||||||
|
|
||||||
if os.getuid() == 0:
|
if os.getuid() == 0:
|
||||||
|
|
@ -87,20 +108,24 @@ def fuse_test_marker():
|
||||||
|
|
||||||
mode = os.stat(fusermount_path).st_mode
|
mode = os.stat(fusermount_path).st_mode
|
||||||
if mode & stat.S_ISUID == 0:
|
if mode & stat.S_ISUID == 0:
|
||||||
return skip('fusermount executable not setuid, and we are not root.')
|
return skip("fusermount executable not setuid, and we are not root.")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
fd = os.open('/dev/fuse', os.O_RDWR)
|
fd = os.open("/dev/fuse", os.O_RDWR)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
return skip('Unable to open /dev/fuse: %s' % exc.strerror)
|
return skip(f"Unable to open /dev/fuse: {exc.strerror}")
|
||||||
else:
|
else:
|
||||||
os.close(fd)
|
os.close(fd)
|
||||||
|
|
||||||
return pytest.mark.uses_fuse()
|
return pytest.mark.uses_fuse()
|
||||||
|
|
||||||
|
|
||||||
# Use valgrind if requested
|
# Use valgrind if requested
|
||||||
if os.environ.get('TEST_WITH_VALGRIND', 'no').lower().strip() \
|
if os.environ.get("TEST_WITH_VALGRIND", "no").lower().strip() not in (
|
||||||
not in ('no', 'false', '0'):
|
"no",
|
||||||
base_cmdline = [ 'valgrind', '-q', '--' ]
|
"false",
|
||||||
|
"0",
|
||||||
|
):
|
||||||
|
base_cmdline = ["valgrind", "-q", "--"]
|
||||||
else:
|
else:
|
||||||
base_cmdline = []
|
base_cmdline = []
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue