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

.

parent eeb7a544
...@@ -3,11 +3,6 @@ ...@@ -3,11 +3,6 @@
storv = ['fs', 'zeo', 'neo'] # storage backends to test against 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. # 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. # we don't run test.vg* because there is currently no valgrind on SlapOS.
for kind in ['t', 'fault', 'asan', 'tsan']: for kind in ['t', 'fault', 'asan', 'tsan']:
...@@ -34,20 +29,30 @@ for stor in storv: ...@@ -34,20 +29,30 @@ for stor in storv:
# test.go unit-tests Go bits in wcfs. # test.go unit-tests Go bits in wcfs.
for nproc in gonprocv: TestCase('test.go', ['make', 'test.go'])
TestCase('test.go:%s' % nproc, ['make', 'test.go'],
envadj={'GOMAXPROCS': nproc})
# test.wcfs/<stor> runs unit tests for WCFS # test.wcfs/<stor> runs unit tests for WCFS
# test.py/<stor>-wcfs runs unit- and functional- tests for wendelin.core in wcfs mode. # test.py/<stor>-wcfs runs unit- and functional- tests for wendelin.core in wcfs mode.
for stor in storv: 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: for nproc in gonprocv:
TestCase('test.wcfs/%s:%s' % (stor, nproc), ['make', 'test.wcfs'], 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: for nproc in gonprocv:
TestCase('test.py/%s-wcfs:%s' % (stor, nproc), ['make', 'test.py'], 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) summaryf=PyTest.summary)
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
all : all :
PYTHON ?= python PYTHON ?= python
PYTEST ?= $(PYTHON) -m pytest -vs PYTEST ?= $(PYTHON) -m pytest
PYBENCH ?= $(PYTHON) -m golang.cmd.pybench PYBENCH ?= $(PYTHON) -m golang.cmd.pybench
VALGRIND?= valgrind VALGRIND?= valgrind
GO ?= go GO ?= go
......
...@@ -24,7 +24,7 @@ import pytest ...@@ -24,7 +24,7 @@ import pytest
import transaction import transaction
from golang import func, defer from golang import func, defer
from functools import partial from functools import partial
import gc import os, gc
# reset transaction synchronizers before every test run. # reset transaction synchronizers before every test run.
# #
...@@ -46,9 +46,24 @@ def transaction_reset(): ...@@ -46,9 +46,24 @@ def transaction_reset():
# nothing to run after test # 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 # enable log_cli on no-capture
# (output during a test is a mixture of print and log) # (output during a test is a mixture of print and log)
def pytest_configure(config): 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": if config.option.capture == "no":
config.inicfg['log_cli'] = "true" config.inicfg['log_cli'] = "true"
assert config.getini("log_cli") is True assert config.getini("log_cli") is True
......
...@@ -292,14 +292,17 @@ class TestDB_NEO(TestDB_Base): ...@@ -292,14 +292,17 @@ class TestDB_NEO(TestDB_Base):
def __init__(self, dburi): def __init__(self, dburi):
super(TestDB_NEO, self).__init__(dburi) super(TestDB_NEO, self).__init__(dburi)
from neo.tests.functional import NEOCluster from neo.tests.functional import NEOCluster
self.cluster = NEOCluster(['1'], adapter='SQLite') self.NEOCluster = NEOCluster
def setup(self): def setup(self):
self.tmpd = mkdtemp('', 'testdb_neo.')
self.cluster = self.NEOCluster(['1'], temp_dir=self.tmpd, adapter='SQLite')
self.cluster.start() self.cluster.start()
self.cluster.expectClusterRunning() self.cluster.expectClusterRunning()
def _teardown(self): def _teardown(self):
self.cluster.stop() self.cluster.stop()
rmtree(self.tmpd)
def getZODBStorage(self): def getZODBStorage(self):
return self.cluster.getZODBStorage() return self.cluster.getZODBStorage()
......
...@@ -246,11 +246,11 @@ def git_lsfiles(dirname): ...@@ -246,11 +246,11 @@ def git_lsfiles(dirname):
# FIXME dirname is currently ignored # FIXME dirname is currently ignored
# XXX non-ascii names, etc # XXX non-ascii names, etc
for _ in runcmd(['git', 'ls-files']).splitlines(): for _ in runcmd(['git', 'ls-files']).splitlines():
yield _.decode('utf8') # XXX utf8 hardcoded yield _
# XXX recursive submodules # XXX recursive submodules
for _ in runcmd(['git', 'submodule', 'foreach', '--quiet', \ for _ in runcmd(['git', 'submodule', 'foreach', '--quiet', \
r'git ls-files | sed "s|\(.*\)\$|$path/\1|g"']).splitlines(): 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 # if we are in git checkout - inject git_lsfiles to setuptools.file_finders
# entry-point on the fly. # entry-point on the fly.
......
...@@ -417,6 +417,24 @@ def __stop(wcsrv, ctx, _onstuck): ...@@ -417,6 +417,24 @@ def __stop(wcsrv, ctx, _onstuck):
# unmount and wait for wcfs to exit # unmount and wait for wcfs to exit
# kill wcfs and abort FUSE connection if clean unmount fails # 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 _(): def _():
if wcsrv._fuseabort is not None: if wcsrv._fuseabort is not None:
wcsrv._fuseabort.close() wcsrv._fuseabort.close()
...@@ -521,10 +539,20 @@ def _mkdir_p(path, mode=0o777): # -> created(bool) ...@@ -521,10 +539,20 @@ def _mkdir_p(path, mode=0o777): # -> created(bool)
return False return False
return True 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. # _fuse_unmount calls `fusermount -u` + logs details if unmount failed.
#
# Additional options to fusermount can be passed via optv.
@func @func
def _fuse_unmount(mntpt): def _fuse_unmount(mntpt, *optv):
ret, out = _sysproccallout(["fusermount", "-u", mntpt]) ret, out = _sysproccallout(["fusermount", "-u"] + list(optv) + [mntpt])
if ret != 0: if ret != 0:
# unmount failed, usually due to "device is busy". # unmount failed, usually due to "device is busy".
# Log which files are still opened and reraise # Log which files are still opened and reraise
...@@ -543,7 +571,10 @@ def _fuse_unmount(mntpt): ...@@ -543,7 +571,10 @@ def _fuse_unmount(mntpt):
defer(_) defer(_)
out = out.rstrip() # kill trailing \n\n 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) log.warn(emsg)
raise RuntimeError("%s\n(more details logged)" % emsg) raise RuntimeError("%s\n(more details logged)" % emsg)
...@@ -713,6 +744,7 @@ def main(): ...@@ -713,6 +744,7 @@ def main():
elif cmd == "stop": elif cmd == "stop":
mntpt = _mntpt_4zurl(zurl) mntpt = _mntpt_4zurl(zurl)
_fuse_unmount(mntpt) _fuse_unmount(mntpt)
_rmdir_ifexists(mntpt)
else: else:
print("wcfs: unknown command %s" % qq(cmd), file=sys.stderr) print("wcfs: unknown command %s" % qq(cmd), file=sys.stderr)
......
...@@ -53,7 +53,7 @@ from pytest import raises, fail ...@@ -53,7 +53,7 @@ from pytest import raises, fail
from wendelin.wcfs.internal import io, mm 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.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.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: # setup:
...@@ -106,8 +106,7 @@ def teardown_function(f): ...@@ -106,8 +106,7 @@ def teardown_function(f):
mounted = is_mountpoint(testmntpt) mounted = is_mountpoint(testmntpt)
if mounted: if mounted:
fuse_unmount(testmntpt) fuse_unmount(testmntpt)
if os.path.exists(testmntpt): rmdir_ifexists(testmntpt)
os.rmdir(testmntpt)
with raises(KeyError): with raises(KeyError):
procmounts_lookup_wcfs(testzurl) procmounts_lookup_wcfs(testzurl)
...@@ -384,7 +383,6 @@ class tWCFS(_tWCFS): ...@@ -384,7 +383,6 @@ class tWCFS(_tWCFS):
if is_mountpoint(t.wc.mountpoint): if is_mountpoint(t.wc.mountpoint):
fuse_unmount(t.wc.mountpoint) fuse_unmount(t.wc.mountpoint)
assert not is_mountpoint(t.wc.mountpoint) assert not is_mountpoint(t.wc.mountpoint)
os.rmdir(t.wc.mountpoint)
defer(_) defer(_)
def _(): def _():
def onstuck(): 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