Commit 257018a5 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent eeb7a544
......@@ -3,11 +3,6 @@
storv = ['fs', 'zeo', 'neo'] # storage backends to test against
# some bugs are only likely to trigger when there is only 1 or 2 main OS thread(s) in wcfs
# GOMAXPROCS='' means use `nproc`
gonprocv = ['1', '2', ''] # GOMAXPROCS=... to test against
# test.t & friends unit-test core of UVMM and are Go-, Python- and ZODB-storage independent.
# we don't run test.vg* because there is currently no valgrind on SlapOS.
for kind in ['t', 'fault', 'asan', 'tsan']:
......@@ -34,20 +29,30 @@ for stor in storv:
# test.go unit-tests Go bits in wcfs.
for nproc in gonprocv:
TestCase('test.go:%s' % nproc, ['make', 'test.go'],
envadj={'GOMAXPROCS': nproc})
TestCase('test.go', ['make', 'test.go'])
# test.wcfs/<stor> runs unit tests for WCFS
# test.py/<stor>-wcfs runs unit- and functional- tests for wendelin.core in wcfs mode.
for stor in storv:
envdb = {'WENDELIN_CORE_TEST_DB': '<%s>' % stor}
env = {
'WENDELIN_CORE_TEST_DB': '<%s>' % stor,
# run in verbose mode and don't capture output in the early days of WCFS
#
# non-capture is needed because if WCFS gets stuck somehow on testnode, we
# still want to see some test output instead of full silence and pytest
# being killed after 4 hours of timeout.
'PYTEST_ADDOPTS': '-vs',
}
# some bugs are only likely to trigger when there is only 1 or 2 main OS thread(s) in wcfs
# GOMAXPROCS='' means use `nproc`
gonprocv = ['1', '2', ''] # GOMAXPROCS=... to test against
for nproc in gonprocv:
TestCase('test.wcfs/%s:%s' % (stor, nproc), ['make', 'test.wcfs'],
envadj=dict(GOMAXPROCS=nproc, **envdb), summaryf=PyTest.summary)
envadj=dict(GOMAXPROCS=nproc, **env), summaryf=PyTest.summary)
for nproc in gonprocv:
TestCase('test.py/%s-wcfs:%s' % (stor, nproc), ['make', 'test.py'],
envadj=dict(WENDELIN_CORE_VIRTMEM='r:wcfs+w:uvmm', GOMAXPROCS=nproc, **envdb),
envadj=dict(WENDELIN_CORE_VIRTMEM='r:wcfs+w:uvmm', GOMAXPROCS=nproc, **env),
summaryf=PyTest.summary)
......@@ -20,7 +20,7 @@
all :
PYTHON ?= python
PYTEST ?= $(PYTHON) -m pytest -vs
PYTEST ?= $(PYTHON) -m pytest
PYBENCH ?= $(PYTHON) -m golang.cmd.pybench
VALGRIND?= valgrind
GO ?= go
......
......@@ -24,7 +24,7 @@ import pytest
import transaction
from golang import func, defer
from functools import partial
import gc
import os, gc
# reset transaction synchronizers before every test run.
#
......@@ -46,9 +46,24 @@ def transaction_reset():
# nothing to run after test
# prepend_env prepends prefix + ' ' to environment variable var.
def prepend_env(var, prefix):
v = os.environ.get(var, '')
if v != '':
v = ' ' + v
v = prefix + v
os.environ[var] = v
# enable log_cli on no-capture
# (output during a test is a mixture of print and log)
def pytest_configure(config):
# put WCFS log into stderr instead of to many files in /tmp/wcfs.*.log
# this way we don't leak those files and include relevant information in test output
#
# TODO put WCFS logs into dedicated dir without -v?
prepend_env('WENDELIN_CORE_WCFS_OPTIONS', '-logtostderr')
if config.option.capture == "no":
config.inicfg['log_cli'] = "true"
assert config.getini("log_cli") is True
......
......@@ -292,14 +292,17 @@ class TestDB_NEO(TestDB_Base):
def __init__(self, dburi):
super(TestDB_NEO, self).__init__(dburi)
from neo.tests.functional import NEOCluster
self.cluster = NEOCluster(['1'], adapter='SQLite')
self.NEOCluster = NEOCluster
def setup(self):
self.tmpd = mkdtemp('', 'testdb_neo.')
self.cluster = self.NEOCluster(['1'], temp_dir=self.tmpd, adapter='SQLite')
self.cluster.start()
self.cluster.expectClusterRunning()
def _teardown(self):
self.cluster.stop()
rmtree(self.tmpd)
def getZODBStorage(self):
return self.cluster.getZODBStorage()
......
......@@ -246,11 +246,11 @@ def git_lsfiles(dirname):
# FIXME dirname is currently ignored
# XXX non-ascii names, etc
for _ in runcmd(['git', 'ls-files']).splitlines():
yield _.decode('utf8') # XXX utf8 hardcoded
yield _
# XXX recursive submodules
for _ in runcmd(['git', 'submodule', 'foreach', '--quiet', \
r'git ls-files | sed "s|\(.*\)\$|$path/\1|g"']).splitlines():
yield _.decode('utf8') # XXX utf8 hardcoded
yield _
# if we are in git checkout - inject git_lsfiles to setuptools.file_finders
# entry-point on the fly.
......
......@@ -417,6 +417,24 @@ def __stop(wcsrv, ctx, _onstuck):
# unmount and wait for wcfs to exit
# kill wcfs and abort FUSE connection if clean unmount fails
# at the end make sure mount entry and mountpoint directory are removed
def _():
# when stop runs:
# - wcsrv could be already `fusermount -u`'ed from outside
# - the mountpoint could be also already removed from outside
_rmdir_ifexists(wcsrv.mountpoint)
defer(_)
def _():
# second unmount, if first unmount failed and we had to abort FUSE connection
# -z (lazy) because this one has to succeed, but there could be still
# client file descriptors left pointing to the mounted filesystem.
if _is_mountpoint(wcsrv.mountpoint):
log.warn("-> unmount -z ...")
_fuse_unmount(wcsrv.mountpoint, "-z")
defer(_)
def _():
if wcsrv._fuseabort is not None:
wcsrv._fuseabort.close()
......@@ -521,10 +539,20 @@ def _mkdir_p(path, mode=0o777): # -> created(bool)
return False
return True
# rmdir if path exists.
def _rmdir_ifexists(path):
try:
os.rmdir(path)
except OSError as e:
if e.errno != ENOENT:
raise
# _fuse_unmount calls `fusermount -u` + logs details if unmount failed.
#
# Additional options to fusermount can be passed via optv.
@func
def _fuse_unmount(mntpt):
ret, out = _sysproccallout(["fusermount", "-u", mntpt])
def _fuse_unmount(mntpt, *optv):
ret, out = _sysproccallout(["fusermount", "-u"] + list(optv) + [mntpt])
if ret != 0:
# unmount failed, usually due to "device is busy".
# Log which files are still opened and reraise
......@@ -543,7 +571,10 @@ def _fuse_unmount(mntpt):
defer(_)
out = out.rstrip() # kill trailing \n\n
emsg = "fuse_unmount %s: failed: %s" % (mntpt, out)
opts = ' '.join(optv)
if opts != '':
opts += ' '
emsg = "fuse_unmount %s%s: failed: %s" % (opts, mntpt, out)
log.warn(emsg)
raise RuntimeError("%s\n(more details logged)" % emsg)
......@@ -713,6 +744,7 @@ def main():
elif cmd == "stop":
mntpt = _mntpt_4zurl(zurl)
_fuse_unmount(mntpt)
_rmdir_ifexists(mntpt)
else:
print("wcfs: unknown command %s" % qq(cmd), file=sys.stderr)
......
......@@ -53,7 +53,7 @@ from pytest import raises, fail
from wendelin.wcfs.internal import io, mm
from wendelin.wcfs.internal.wcfs_test import _tWCFS, read_exfault_nogil, SegmentationFault, install_sigbus_trap, fadvise_dontneed
from wendelin.wcfs.client._wcfs import _tpywlinkwrite as _twlinkwrite
from wendelin.wcfs import _is_mountpoint as is_mountpoint, _procwait as procwait, _ready as ready
from wendelin.wcfs import _is_mountpoint as is_mountpoint, _procwait as procwait, _ready as ready, _rmdir_ifexists as rmdir_ifexists
# setup:
......@@ -106,8 +106,7 @@ def teardown_function(f):
mounted = is_mountpoint(testmntpt)
if mounted:
fuse_unmount(testmntpt)
if os.path.exists(testmntpt):
os.rmdir(testmntpt)
rmdir_ifexists(testmntpt)
with raises(KeyError):
procmounts_lookup_wcfs(testzurl)
......@@ -384,7 +383,6 @@ class tWCFS(_tWCFS):
if is_mountpoint(t.wc.mountpoint):
fuse_unmount(t.wc.mountpoint)
assert not is_mountpoint(t.wc.mountpoint)
os.rmdir(t.wc.mountpoint)
defer(_)
def _():
def onstuck():
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment