Commit 00f8607e authored by Levin Zimmermann's avatar Levin Zimmermann

software/erp5/tests: Extend WCFS test scope

This patch enhances the ERP5 + WCFS integration tests. Before it was
only minimal; now it runs actual workload of writing and reading
ZBigArray to the ZODB. This is necessary to securely verify WC2 is
working with ERP5.

We had to implement the new tests in a separate test environment,
because SlapOS Integration tests run with python3, but we need python2
for NEO support. We need NEO, because we want to test if WCFS works with
NEO client.
parent e11c60aa
[buildout]
extends =
{{ template_erp5 }}
[publish-early]
erp5-wcfs-test-bin = {{ erp5_wcfs_test_bin }}
[buildout]
extends =
{{ template }}
[dynamic-template-erp5-test-parameters]
bin = {{ erp5_wcfs_test_bin }}
[dynamic-template-erp5-test]
<= jinja2-template-base
url = {{ template_erp5_test }}
filename = instance-erp5-test.cfg
extra-context =
key template_erp5 dynamic-template-erp5:output
key erp5_wcfs_test_bin dynamic-template-erp5-test-parameters:bin
[switch-softwaretype]
default = dynamic-template-erp5-test:output
[buildout] [buildout]
extends = extends =
../../component/pytest/buildout.cfg
software.cfg software.cfg
parts +=
template-test
# Pick ZODB version which is compatible with both erp5/py2 + WCFS # Pick ZODB version which is compatible with both erp5/py2 + WCFS
[ZODB] [ZODB]
...@@ -10,3 +13,65 @@ major = 4-wc2 ...@@ -10,3 +13,65 @@ major = 4-wc2
[neoppod-repository] [neoppod-repository]
repository = https://lab.nexedi.com/kirr/neo.git repository = https://lab.nexedi.com/kirr/neo.git
branch = t branch = t
# We want to use master branch of wendelin.core with all
# recent commits.
[wendelin.core-repository]
revision =
# We use external standalone test program to verify WCFS is working
# as expected. We can't use the default erp5 test suite, because this
# test suite runs with py3. We need NEO for testing, but NEO doesn't
# support py3 yet.
[template-erp5-test]
<= download-base
url = ${:_profile_base_location_}/instance-erp5-test.cfg.in
[template]
output = ${buildout:directory}/_template.cfg
[template-test]
recipe = slapos.recipe.template:jinja2
url = ${:_profile_base_location_}/instance-test.cfg.in
output = ${buildout:directory}/template.cfg
md5sum = 92c7f13734c921bb27002579222268b1
context =
key template template:output
key template_erp5_test template-erp5-test:target
key erp5_wcfs_test_bin erp5-wcfs-test:bin
[erp5-wcfs-test]
<= eggs
eggs =
${pytest:eggs}
${erp5-wcfs-test-egg:egg}
ZODB3
script-name = ${:_buildout_section_name_}
entry-points = ${:script-name}=__main__:main
initialization =
import os
import sys
import pytest
# Explicitly turn on WCFS mode
os.environ["WENDELIN_CORE_VIRTMEM"] = "r:wcfs+w:uvmm"
# WCFS should already run!
os.environ["WENDELIN_CORE_WCFS_AUTOSTART"] = "no"
zurl = sys.argv[1]
error_code = pytest.main(["--zurl", zurl, "${erp5-wcfs-test-egg:setup}"])
sys.exit(error_code)
bin = ${buildout:bin-directory}/${:script-name}
scripts +=
${:script-name}
[erp5-wcfs-test-egg]
recipe = zc.recipe.egg:develop
egg = slapos.test.erp5_wcfs
setup = ${slapos-repository:location}/software/erp5/test_wcfs/
[slapos-repository]
recipe = slapos.recipe.build:gitclone
git-executable = ${git:location}/bin/git
forbid-download-cache = true
# XXX: Set to master before merging
repository = https://lab.nexedi.com/levin.zimmermann/slapos.git
branch = for_testrunner_1
# Copyright (C) 2021 Nexedi SA and Contributors. # Copyright (C) 2022 Nexedi SA and Contributors.
# #
# This program is free software: you can Use, Study, Modify and Redistribute # 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 # it under the terms of the GNU General Public License version 3, or (at your
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
import json import json
import os.path import os.path
import subprocess
import unittest import unittest
from slapos.grid.utils import md5digest from slapos.grid.utils import md5digest
...@@ -47,20 +48,41 @@ class TestWCFS(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin): ...@@ -47,20 +48,41 @@ class TestWCFS(ERP5InstanceTestCase, TestPublishedURLIsReachableMixin):
def getInstanceParameterDict(cls): def getInstanceParameterDict(cls):
return {'_': json.dumps({'wcfs': {'enable': True}})} return {'_': json.dumps({'wcfs': {'enable': True}})}
def getZUrl(self):
return json.loads(
self.getComputerPartition('wcfs').getConnectionParameter('_')
)['serving-zurl']
def test_wcfs_accessible(self): def test_wcfs_accessible(self):
"""Verify that wcfs filesystem is basically accessible. """Verify that wcfs filesystem is basically accessible.
- we can read .wcfs/zurl - we can read .wcfs/zurl
- its content is equal to published `serving-zurl` - its content is equal to published `serving-zurl`
""" """
zurl = json.loads( zurl = self.getZUrl()
self.getComputerPartition('wcfs').getConnectionParameter('_')
)['serving-zurl']
mntpt = lookupMount(zurl) mntpt = lookupMount(zurl)
zurl_ = readfile("%s/.wcfs/zurl" % mntpt) zurl_ = readfile("%s/.wcfs/zurl" % mntpt)
self.assertEqual(zurl_, zurl) self.assertEqual(zurl_, zurl)
def test_workload(self):
"""Verify simple workload (reading/writing operation) on WCFS is successful"""
# Run sub-testsuite in software/erp5/test_wcfs/test.
wcfs_test_bin = self.getRootPartitionConnectionParameterDict()[
'erp5-wcfs-test-bin'
]
try:
exit_code = subprocess.run(
[wcfs_test_bin, self.getZUrl()],
stdout=subprocess.PIPE,
check=True,
).returncode
except subprocess.CalledProcessError as e:
exit_code = 1
failure_info = e.stdout.decode()
else:
failure_info = ""
self.assertEqual(0, exit_code, failure_info)
# lookupMount returns /proc/mount entry for wcfs mounted to serve zurl. # lookupMount returns /proc/mount entry for wcfs mounted to serve zurl.
def lookupMount(zurl): def lookupMount(zurl):
......
# Test wendelin.core v2 integration with ERP5 SR
This test suite is called by `software/erp5/test`.
The complete logic is:
ERP5 `test.cfg` SR creates a `python` with all necessary eggs and installs a `bin` which executes this test suite.
The location of this `bin` is communicated to the outside world by publishing it as a connection parameter.
SlapOS integration test `software/erp5/test` reads the location of the script by fetching connection parameters.
It calls the script and provides the script the zurl of the ZODB storage.
The script runs the test suite and returns an exit code, 0 if the test suite succeeded and 1 if it failed.
If the exit code is 0 the unit test is passed.
def pytest_addoption(parser):
parser.addoption("--zurl", action="store")
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from setuptools import setup, find_packages
version = '0.0.1.dev0'
name = 'slapos.test.erp5_wcfs'
with open("README.md") as f:
long_description = f.read()
setup(name=name,
version=version,
description="Test WCFS integration in SlapOS' ERP5 software release",
long_description=long_description,
long_description_content_type='text/markdown',
maintainer="Nexedi",
maintainer_email="info@nexedi.com",
url="https://lab.nexedi.com/nexedi/slapos",
packages=find_packages(),
install_requires=[
'ZODB',
'numpy',
'wendelin.core',
'ZEO',
'neoppod',
],
)
##############################################################################
#
# Copyright (c) 2022 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from collections import namedtuple
import pytest
import numpy as np
from wendelin.bigarray.array_zodb import ZBigArray
from wendelin.lib.zodb import dbopen, dbclose
from wendelin.wcfs import join
from ZODB import DB
from golang import defer, func
import transaction
@func
def test_data_is_written_to_wcfs(zurl):
"""Minimal test: data is written to WCFS"""
_ = getRunner(zurl)
defer(lambda: _(cleanup))
def cleanup(root):
if hasattr(root, 'zarray'):
del root.zarray; transaction.commit()
@_
def zarray(root):
assert not hasattr(root, 'zarray')
root.zarray = zarray = ZBigArray(shape=(4,), dtype=int)
transaction.commit()
zarray.append([0, 0, 0, 0])
transaction.commit()
return zarray
wcfs = join(zurl); defer(wcfs.close)
assert wcfs._read(zarray.zfile)
stat = wcfs._stat(zarray.zfile)
assert stat.st_blksize == zarray.zfile.blksize
assert stat.st_size == zarray.zfile.blksize
@func
def test_array_read_write_modify(zurl):
"""Verify writing/reading ZBigArray to/from ZODB works."""
_ = getRunner(zurl)
defer(lambda: _(cleanup))
def cleanup(root):
if hasattr(root, 'zarray'):
del root.zarray; transaction.commit()
@_
def create_array_and_commit(root):
assert not hasattr(root, 'zarray')
root.zarray = ZBigArray(shape=(4,), dtype=int)
transaction.commit()
@_
def verify_array_has_been_written_to_zodb(root):
assert hasattr(root, 'zarray')
assert root.zarray.shape, (4,)
np.testing.assert_array_equal(root.zarray[:], [0,0,0,0])
@_
def mutate_array_and_commit(root):
root.zarray[:][0] = 100; transaction.commit()
@_
def verify_mutation_has_been_written_to_zodb(root):
assert root.zarray[:][0] == 100
@pytest.fixture(scope="session")
def zurl(pytestconfig):
return pytestconfig.getoption("zurl")
def getRunner(zurl):
@func
def run(func):
root = dbopen(zurl)
defer(lambda: dbclose(root))
return func(root)
return run
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