Commit a8fa9178 authored by Kirill Smelkov's avatar Kirill Smelkov

X wcfs: move client tests into client/

parent 0a8fcd9d
# -*- coding: utf-8 -*-
# Copyright (C) 2018-2020 Nexedi SA and Contributors.
# Kirill Smelkov <kirr@nexedi.com>
#
# This program is free software: you can Use, Study, Modify and Redistribute
# it under the terms of the GNU General Public License version 3, or (at your
# option) any later version, as published by the Free Software Foundation.
#
# You can also Link and Combine this program with other software covered by
# the terms of any of the Free Software licenses or any of the Open Source
# Initiative approved licenses and Convey the resulting work. Corresponding
# source of such a combination shall include the source code for all other
# software used.
#
# This program is distributed WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""client_test.py unit-tests virtmem layer provided by wcfs client.
WCFS filesystem itself is unit-tested by wcfs/wcfs_test.py .
At functional level, the whole wendelin.core test suite is used to verify
wcfs.py/wcfs.go while running tox tests in wcfs mode.
"""
from __future__ import print_function, absolute_import
from golang import func, defer
from wendelin.wcfs.wcfs_test import tDB, tAt
from wendelin.wcfs import wcfs_test
# XXX so that e.g. testdb is set up + ...
def setup_module(): wcfs_test.setup_module()
def teardown_module(): wcfs_test.teardown_module()
def setup_function(f): wcfs_test.setup_function(f)
def teardown_function(f): wcfs_test.teardown_function(f)
# tMapping provides testing environment for Mapping.
class tMapping(object):
def __init__(t, tdb, mmap):
t.tdb = tdb
t.mmap = mmap
# XXX assertCache
# assertBlk asserts that mmap[·] with · corresponding to blk reads as dataok.
# pinnedOK: {} blk -> rev of t.mmap.fileh.pinned after access.
#
# see also: tFile.assertBlk .
# NOTE contrary to tFile, pinnedOK represents full fh.pinned state, not
# only pins that wcfs sent to client after tested access.
def assertBlk(t, blk, dataok, pinnedOK):
assert t.mmap.blk_start <= blk < t.mmap.blk_stop
blk_inmmap = blk - t.mmap.blk_start
if not isinstance(dataok, bytes):
dataok = dataok.encode('utf-8')
fh = t.mmap.fileh
assert len(dataok) <= fh.blksize
dataok += b'\0'*(fh.blksize - len(dataok)) # trailing zeros
blkview = t.mmap.mem[blk_inmmap*fh.blksize:][:fh.blksize]
# NOTE access to memory goes _with_ GIL: this verifies that wcfs pinner
# is implemented in fully nogil mode because if that was not the case,
# the pinner would deadlock trying to acquire GIL in its thread while
# user thread that triggered the access is already holding the GIL.
#
# - - - - - -
# | |
# pinner <------.
# | | wcfs
# client -------^
# | |
# - - - - - -
# client process
#
_ = blkview[0]
assert _ == dataok[0]
assert blkview.tobytes() == dataok
assert fhpinned(t.tdb, fh) == pinnedOK
# XXX assertData
# fhpinned(fh) returns fh.pinned with rev wrapped into tAt.
# XXX better wrap FileH into tFileH and do this automatically in .pinned ?
def fhpinned(t, fh):
p = fh.pinned.copy()
for blk in p:
p[blk] = tAt(t, p[blk])
return p
# test_wcfs_virtmem unit-tests virtmem layer of wcfs client.
@func
def test_wcfs_virtmem():
t = tDB(); zf = t.zfile; at0=t.at0
defer(t.close)
pinned = lambda fh: fhpinned(t, fh)
at1 = t.commit(zf, {2:'c1', 3:'d1'})
at2 = t.commit(zf, {2:'c2'})
wconn = t.wc.connect(at1)
defer(wconn.close)
fh = wconn.open(zf._p_oid)
defer(fh.close)
# create mmap with 1 block beyond file size
m1 = fh.mmap(2, 3)
defer(m1.unmap)
assert m1.blk_start == 2
assert m1.blk_stop == 5
assert len(m1.mem) == 3*zf.blksize
tm1 = tMapping(t, m1)
#assertCache(m1, [0,0,0])
assert pinned(fh) == {}
# verify initial data reads
tm1.assertBlk(2, 'c1', {2:at1})
tm1.assertBlk(3, 'd1', {2:at1})
tm1.assertBlk(4, '', {2:at1})
# commit with growing file size -> verify data read as the same, #3 pinned.
# (#4 is not yet pinned because it was not accessed)
at3 = t.commit(zf, {3:'d3', 4:'e3'})
assert pinned(fh) == {2:at1}
tm1.assertBlk(2, 'c1', {2:at1})
tm1.assertBlk(3, 'd1', {2:at1, 3:at1})
tm1.assertBlk(4, '', {2:at1, 3:at1})
# resync at1 -> at2: #2 must unpin to @head; #4 must stay as zero
wconn.resync(at2)
assert pinned(fh) == {3:at1}
tm1.assertBlk(2, 'c2', { 3:at1})
tm1.assertBlk(3, 'd1', { 3:at1})
tm1.assertBlk(4, '', { 3:at1, 4:at0}) # XXX at0->ø ?
# resync at2 -> at3: #3 must unpin to @head; #4 - start to read with data
wconn.resync(at3)
assert pinned(fh) == {}
tm1.assertBlk(2, 'c2', {})
tm1.assertBlk(3, 'd3', {})
tm1.assertBlk(4, 'e3', {})
# XXX resync ↓ ?
# XXX mmap after .size completely (start > size)
# XXX w mapping with RW - in sync
# XXX fh close then open again and use
# XXX open same fh twice, close once - fh2 continue to work ok
# XXX wconn.open() after wconn.close() -> error
# XXX wconn.resync() after wconn.close() -> error
# XXX all fileh / mappings become invalid after wconn.close
......@@ -17,9 +17,10 @@
#
# See COPYING file for full licensing terms.
# See https://www.nexedi.com/licensing for rationale and options.
"""wcfs_test tests wcfs filesystem from outside as python client process
"""wcfs_test.py tests wcfs filesystem from outside as python client process.
It also unit-tests virtmem layer of wcfs virtmem client.
Virtmem layer provided by wcfs client package is unit-tested by
wcfs/client/client_test.py .
At functional level, the whole wendelin.core test suite is used to verify
wcfs.py/wcfs.go while running tox tests in wcfs mode.
......@@ -1697,136 +1698,6 @@ def test_wcfs_watch_2files():
# XXX @revX/ is automatically removed after some time
# ---- unit-tests for virtmem layer of wcfs client ----
# tMapping provides testing environment for Mapping.
class tMapping(object):
def __init__(t, tdb, mmap):
t.tdb = tdb
t.mmap = mmap
# XXX assertCache
# assertBlk asserts that mmap[·] with · corresponding to blk reads as dataok.
# pinnedOK: {} blk -> rev of t.mmap.fileh.pinned after access.
#
# see also: tFile.assertBlk .
# NOTE contrary to tFile, pinnedOK represents full fh.pinned state, not
# only pins that wcfs sent to client after tested access.
def assertBlk(t, blk, dataok, pinnedOK):
assert t.mmap.blk_start <= blk < t.mmap.blk_stop
blk_inmmap = blk - t.mmap.blk_start
if not isinstance(dataok, bytes):
dataok = dataok.encode('utf-8')
fh = t.mmap.fileh
assert len(dataok) <= fh.blksize
dataok += b'\0'*(fh.blksize - len(dataok)) # trailing zeros
blkview = t.mmap.mem[blk_inmmap*fh.blksize:][:fh.blksize]
# NOTE access to memory goes _with_ GIL: this verifies that wcfs pinner
# is implemented in fully nogil mode because if that was not the case,
# the pinner would deadlock trying to acquire GIL in its thread while
# user thread that triggered the access is already holding the GIL.
#
# - - - - - -
# | |
# pinner <------.
# | | wcfs
# client -------^
# | |
# - - - - - -
# client process
#
_ = blkview[0]
assert _ == dataok[0]
assert blkview.tobytes() == dataok
assert fhpinned(t.tdb, fh) == pinnedOK
# XXX assertData
# fhpinned(fh) returns fh.pinned with rev wrapped into tAt.
# XXX better wrap FileH into tFileH and do this automatically in .pinned ?
def fhpinned(t, fh):
p = fh.pinned.copy()
for blk in p:
p[blk] = tAt(t, p[blk])
return p
# test_wcfs_virtmem unit-tests virtmem layer of wcfs client.
@func
def test_wcfs_virtmem():
t = tDB(); zf = t.zfile; at0=t.at0
defer(t.close)
pinned = lambda fh: fhpinned(t, fh)
at1 = t.commit(zf, {2:'c1', 3:'d1'})
at2 = t.commit(zf, {2:'c2'})
wconn = t.wc.connect(at1)
defer(wconn.close)
fh = wconn.open(zf._p_oid)
defer(fh.close)
# create mmap with 1 block beyond file size
m1 = fh.mmap(2, 3)
defer(m1.unmap)
assert m1.blk_start == 2
assert m1.blk_stop == 5
assert len(m1.mem) == 3*zf.blksize
tm1 = tMapping(t, m1)
#assertCache(m1, [0,0,0])
assert pinned(fh) == {}
# verify initial data reads
tm1.assertBlk(2, 'c1', {2:at1})
tm1.assertBlk(3, 'd1', {2:at1})
tm1.assertBlk(4, '', {2:at1})
# commit with growing file size -> verify data read as the same, #3 pinned.
# (#4 is not yet pinned because it was not accessed)
at3 = t.commit(zf, {3:'d3', 4:'e3'})
assert pinned(fh) == {2:at1}
tm1.assertBlk(2, 'c1', {2:at1})
tm1.assertBlk(3, 'd1', {2:at1, 3:at1})
tm1.assertBlk(4, '', {2:at1, 3:at1})
# resync at1 -> at2: #2 must unpin to @head; #4 must stay as zero
wconn.resync(at2)
assert pinned(fh) == {3:at1}
tm1.assertBlk(2, 'c2', { 3:at1})
tm1.assertBlk(3, 'd1', { 3:at1})
tm1.assertBlk(4, '', { 3:at1, 4:at0}) # XXX at0->ø ?
# resync at2 -> at3: #3 must unpin to @head; #4 - start to read with data
wconn.resync(at3)
assert pinned(fh) == {}
tm1.assertBlk(2, 'c2', {})
tm1.assertBlk(3, 'd3', {})
tm1.assertBlk(4, 'e3', {})
# XXX resync ↓ ?
# XXX mmap after .size completely (start > size)
# XXX w mapping with RW - in sync
# XXX fh close then open again and use
# XXX open same fh twice, close once - fh2 continue to work ok
# XXX wconn.open() after wconn.close() -> error
# XXX wconn.resync() after wconn.close() -> error
# XXX all fileh / mappings become invalid after wconn.close
# ---- misc ---
# readfile reads file @ path.
......
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