test path from oca
Some checks failed
ci / main (push) Failing after 1m23s

This commit is contained in:
Tokiniaina 2024-10-24 11:46:29 +03:00
parent 43a909e17f
commit 7577dc2324
26 changed files with 492 additions and 0 deletions

0
tests/__init__.py Normal file
View File

97
tests/common.py Normal file
View File

@ -0,0 +1,97 @@
import ast
import contextlib
import os
import shutil
import subprocess
import tempfile
import textwrap
from pathlib import Path
ODOO_VENV = "/opt/odoo-venv"
test_addons_dir = Path(__file__).parent / "data" / "addons"
odoo_version_info = tuple(map(int, os.environ["ODOO_VERSION"].split(".")))
odoo_bin = "odoo"
@contextlib.contextmanager
def preserve_odoo_rc():
odoo_rc_path = Path(os.environ["ODOO_RC"])
odoo_rc = odoo_rc_path.read_bytes()
try:
yield
finally:
odoo_rc_path.write_bytes(odoo_rc)
@contextlib.contextmanager
def preserve_odoo_venv():
subprocess.check_call(["cp", "-arl", ODOO_VENV, ODOO_VENV + ".org"])
try:
yield
finally:
subprocess.check_call(["rm", "-r", ODOO_VENV])
subprocess.check_call(["mv", ODOO_VENV + ".org", ODOO_VENV])
@contextlib.contextmanager
def make_addons_dir(test_addons):
"""Copy test addons to a temporary directory.
Adjust the addons version to match the Odoo version being tested.
Rename __manifest__.py to __openerp__.py for older Odoo versions.
Add pyproject.toml.
"""
with tempfile.TemporaryDirectory() as tmpdir:
tmppath = Path(tmpdir)
for addon_name in test_addons:
shutil.copytree(test_addons_dir / addon_name, tmppath / addon_name)
# prefix Odoo version
manifest_path = tmppath / addon_name / "__manifest__.py"
manifest = ast.literal_eval(manifest_path.read_text())
manifest["version"] = os.environ["ODOO_VERSION"] + "." + manifest["version"]
manifest_path.write_text(repr(manifest))
if odoo_version_info < (10, 0):
manifest_path.rename(manifest_path.parent / "__openerp__.py")
pyproject_toml_path = tmppath / addon_name / "pyproject.toml"
pyproject_toml_path.write_text(
textwrap.dedent(
"""\
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
"""
)
)
yield tmppath
@contextlib.contextmanager
def install_test_addons(test_addons):
with preserve_odoo_rc(), preserve_odoo_venv(), make_addons_dir(
test_addons
) as addons_dir:
subprocess.check_call(["oca_install_addons"], cwd=addons_dir)
yield addons_dir
def dropdb():
subprocess.check_call(["dropdb", "--if-exists", os.environ["PGDATABASE"]])
def did_run_test_module(output, test_module):
"""Check that a test did run by looking in the Odoo log.
test_module is the full name of the test (addon_name.tests.test_module).
"""
return "odoo.addons." + test_module in output
def make_addon_dist_name(addon_name):
odoo_series = int(os.getenv("ODOO_VERSION").partition(".")[0])
return "odoo{odoo_series}-addon-{name}".format(
name=addon_name,
odoo_series=odoo_series if odoo_series < 15 else "",
)

View File

@ -0,0 +1,4 @@
{
"name": "addon with successful test",
"version": "1.0.0",
}

View File

@ -0,0 +1 @@
from . import test_success

View File

@ -0,0 +1,6 @@
from odoo.tests.common import TransactionCase
class Test(TransactionCase):
def test_success(self):
pass

View File

@ -0,0 +1,4 @@
{
"name": "addon that generates warnings",
"version": "1.0.0",
}

View File

@ -0,0 +1 @@
from . import test_warning

View File

@ -0,0 +1,9 @@
import logging
from odoo.tests.common import TransactionCase
_logger = logging.getLogger(__name__)
class Test(TransactionCase):
def test_log_warning(self):
_logger.warning("This is a warning")

View File

@ -0,0 +1,8 @@
{
"name": "addon_with_deb_dep",
"summary": "Depends on 'nano' debian dependency.",
"version": "1.0.0",
"external_dependencies": {
"deb": ["nano"],
}
}

View File

@ -0,0 +1,11 @@
{
"name": "addon_with_deb_dep2",
"summary": "Depends on 'curl' debian dependency, and on addon_with_deb_dep.",
"version": "1.0.0",
"depends": [
"addon_with_deb_dep",
],
"external_dependencies": {
"deb": ["curl"],
}
}

View File

@ -0,0 +1,5 @@
{
"name": "uninstallable_addon",
"version": "1.0.0",
"installable": False,
}

20
tests/docker-compose.yml Normal file
View File

@ -0,0 +1,20 @@
services:
test:
image: registry.ethumada.com/odoo/odoo17co:latest
# build:
# context: ..
# args:
# codename: jammy
# python_version: "3.10"
# odoo_version: "16.0"
volumes:
- ..:/mnt/odoo
working_dir: /mnt/odoo/tests
depends_on:
- postgres
postgres:
image: postgres
environment:
POSTGRES_USER: odoo
POSTGRES_PASSWORD: odoo
POSTGRES_DB: odoo

2
tests/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
# test requirements
pytest

16
tests/runtests.sh Normal file
View File

@ -0,0 +1,16 @@
#!/bin/bash
set -e
# Run pytest on the tests directory,
# which is assumed to be mounted somewhere in the docker image.
here=$(dirname $0)
testvenv=/tmp/testvenv
/usr/bin/python3 -m venv $testvenv
$testvenv/bin/pip install -r $here/requirements.txt
export PATH=$here/../bin:$PATH
$testvenv/bin/pytest --color=yes --ignore $here/data $here "$@"

19
tests/test_addons_path.py Normal file
View File

@ -0,0 +1,19 @@
import os
import subprocess
from pathlib import Path
from .common import install_test_addons
def test_addons_path():
"""Test must not fail where there are no installable addons."""
assert (
Path(os.environ["ODOO_RC"]).read_text()
== "[options]\n"
)
with install_test_addons(["addon_success"]):
assert (
Path(os.environ["ODOO_RC"]).read_text()
== "[options]\naddons_path=/opt/odoo/addons,.\n"
)
subprocess.check_call(["python", "-c", "import odoo.cli"])

26
tests/test_checklog.py Normal file
View File

@ -0,0 +1,26 @@
import os
import subprocess
from .common import install_test_addons, dropdb, did_run_test_module
def test_checklog_enabled():
"""Test addon_warning with checklog enabled."""
with install_test_addons(["addon_warning"]) as addons_dir:
dropdb()
subprocess.check_call(["oca_init_test_database"], cwd=addons_dir)
os.environ["OCA_ENABLE_CHECKLOG_ODOO"] = "1"
result = subprocess.run(
["oca_run_tests"], cwd=addons_dir, text=True, capture_output=True
)
os.environ["OCA_ENABLE_CHECKLOG_ODOO"] = ""
assert result.returncode == 1 and "Error: Errors detected in log." in result.stderr
def test_checklog_disabled():
"""Test addon_warning with checklog disabled."""
with install_test_addons(["addon_warning"]) as addons_dir:
dropdb()
subprocess.check_call(["oca_init_test_database"], cwd=addons_dir)
result = subprocess.check_output(
["oca_run_tests"], cwd=addons_dir, text=True
)
assert did_run_test_module(result, "addon_warning.tests.test_warning")

View File

@ -0,0 +1,58 @@
import subprocess
import textwrap
from .common import make_addons_dir, make_addon_dist_name
def test_oca_list_addons_to_test_as_url_reqs__basic():
"""Basic successful test."""
with make_addons_dir(
["addon_success", "addon_with_deb_dep", "uninstallable_addon"]
) as addons_dir:
result = subprocess.check_output(
["oca_list_addons_to_test_as_url_reqs"], cwd=addons_dir, text=True
)
assert result == textwrap.dedent(
f"""\
{make_addon_dist_name('addon_success')} @ {addons_dir.as_uri()}/addon_success
{make_addon_dist_name('addon_with_deb_dep')} @ {addons_dir.as_uri()}/addon_with_deb_dep
"""
)
def test_oca_list_addons_to_test_as_url_reqs__editable():
"""Basic successful test with editables."""
with make_addons_dir(
["addon_success", "addon_with_deb_dep", "uninstallable_addon"]
) as addons_dir:
result = subprocess.check_output(
["oca_list_addons_to_test_as_url_reqs", "--editable"],
cwd=addons_dir,
text=True,
)
assert result == textwrap.dedent(
f"""\
-e {addons_dir.as_uri()}/addon_success#egg={make_addon_dist_name('addon_success')}
-e {addons_dir.as_uri()}/addon_with_deb_dep#egg={make_addon_dist_name('addon_with_deb_dep')}
"""
)
def test_oca_list_addons_to_test_as_url_reqs__skip_test_requirement():
"""Basic successful test."""
with make_addons_dir(
["addon_success", "addon_with_deb_dep", "uninstallable_addon"]
) as addons_dir:
# add URL reference to addon_success
addons_dir.joinpath("test-requirements.txt").write_text(
f"{make_addon_dist_name('addon_success')} @ git+https://github.com/oca/dummy@refs/pull/123/head"
)
result = subprocess.check_output(
["oca_list_addons_to_test_as_url_reqs"], cwd=addons_dir, text=True
)
# addon_success should not be in result because it is already in test-requirements.txt
assert result == textwrap.dedent(
f"""\
{make_addon_dist_name('addon_with_deb_dep')} @ {addons_dir.as_uri()}/addon_with_deb_dep
"""
)

View File

@ -0,0 +1,24 @@
from pathlib import Path
import os
import subprocess
from .common import make_addons_dir, preserve_odoo_rc
def test_list_external_dependencies():
with make_addons_dir(["addon_with_deb_dep"]) as addons_dir:
res = subprocess.check_output(
["oca_list_external_dependencies", "deb"], cwd=addons_dir
)
assert res == b"nano\n"
def test_list_external_dependencies_transitive():
"""Test that transitive external dependencies are returned."""
with preserve_odoo_rc(), make_addons_dir(
["addon_with_deb_dep"]
) as dep_addons_dir, make_addons_dir(["addon_with_deb_dep2"]) as addons_dir:
Path(os.getenv("ODOO_RC")).write_text(f"[options]\naddons_path={dep_addons_dir}\n")
res = subprocess.check_output(
["oca_list_external_dependencies", "deb"], cwd=addons_dir
)
assert res == b"curl\nnano\n"

9
tests/test_no_addons.py Normal file
View File

@ -0,0 +1,9 @@
import subprocess
from .common import install_test_addons
def test_no_addons():
"""Test must not fail where there are no installable addons."""
with install_test_addons(["uninstallable_addon"]) as addons_dir:
# no need to initialize test database because tests will not be attempted
subprocess.check_call(["oca_run_tests"], cwd=addons_dir)

View File

@ -0,0 +1,83 @@
from pathlib import Path
import subprocess
import pytest
@pytest.fixture(scope="module")
def repo_dir(tmp_path_factory) -> str:
repo_path = tmp_path_factory.mktemp("repo")
subprocess.check_call(["git", "init"], cwd=repo_path)
subprocess.check_call(
["git", "config", "user.email", "test@example.com"],
cwd=repo_path,
)
subprocess.check_call(
["git", "config", "user.name", "test"],
cwd=repo_path,
)
(repo_path / "README").touch()
subprocess.check_call(["git", "add", "."], cwd=repo_path)
subprocess.check_call(["git", "commit", "-m", "initial commit"], cwd=repo_path)
bare_repo_path = tmp_path_factory.mktemp("bare_repo")
subprocess.check_call(
["git", "clone", "--bare", str(repo_path), str(bare_repo_path)]
)
return str(bare_repo_path)
@pytest.fixture()
def git_clone_path(repo_dir: str, tmp_path) -> Path:
clone_path = tmp_path / "clone"
subprocess.check_call(
["git", "clone", "--depth=1", "file://" + repo_dir, str(clone_path)]
)
subprocess.check_call(
["git", "config", "user.email", "test@example.com"],
cwd=clone_path,
)
subprocess.check_call(
["git", "config", "user.name", "test"],
cwd=clone_path,
)
return clone_path
def test_no_change(git_clone_path: Path):
output = subprocess.check_output(
["oca_git_push_if_remote_did_not_change", "origin"],
cwd=git_clone_path,
text=True,
)
assert "No local change to push" in output
def test_local_change(git_clone_path: Path):
(git_clone_path / "local-change-1").touch()
subprocess.check_call(["git", "add", "."], cwd=git_clone_path)
subprocess.check_call(["git", "commit", "-m", "local-change-1"], cwd=git_clone_path)
output = subprocess.check_output(
["oca_git_push_if_remote_did_not_change", "origin"],
cwd=git_clone_path,
text=True,
)
assert "Pushing changes" in output
def test_remote_change(git_clone_path: Path):
# push a change and reset
(git_clone_path / "remote-change").touch()
subprocess.check_call(["git", "add", "."], cwd=git_clone_path)
subprocess.check_call(["git", "commit", "-m", "remote-change"], cwd=git_clone_path)
subprocess.check_call(["git", "push"], cwd=git_clone_path)
subprocess.check_call(["git", "reset", "--hard", "HEAD^"], cwd=git_clone_path)
# create a local change
(git_clone_path / "local-change-2").touch()
subprocess.check_call(["git", "add", "."], cwd=git_clone_path)
subprocess.check_call(["git", "commit", "-m", "local-change-2"], cwd=git_clone_path)
output = subprocess.check_output(
["oca_git_push_if_remote_did_not_change", "origin"],
cwd=git_clone_path,
text=True,
)
assert "Remote has evolved since we cloned, not pushing" in output

View File

@ -0,0 +1,76 @@
"""Various test that the Dockerfile did what the README promises."""
import os
import shutil
import subprocess
import sys
from pathlib import Path
import pytest
from .common import odoo_bin, make_addons_dir
def test_odoo_bin_in_path():
assert shutil.which(odoo_bin)
def test_wkhtomtopdf_in_path():
assert shutil.which("wkhtmltopdf")
def test_python_in_path():
assert shutil.which("python")
assert Path(shutil.which("python")).parent == Path(shutil.which(odoo_bin)).parent
def test_pip_in_path():
assert shutil.which("pip")
assert Path(shutil.which("pip")).parent == Path(shutil.which(odoo_bin)).parent
def test_addons_dir():
assert os.environ["ADDONS_DIR"] == "."
def test_odoo_rc():
odoo_rc = Path(os.environ["ODOO_RC"])
assert odoo_rc.exists()
assert odoo_rc.read_text() == "[options]\n"
def test_openerp_server_rc():
assert os.environ["OPENERP_SERVER"] == os.environ["ODOO_RC"]
def test_import_odoo():
subprocess.check_call(["python", "-c", "import odoo; odoo.addons.__path__"])
subprocess.check_call(["python", "-c", "import odoo.cli"])
def _target_python_version():
version = subprocess.check_output(
["python", "-c", "import platform; print(platform.python_version())"],
universal_newlines=True,
)
major, minor = version.split(".")[:2]
return int(major), int(minor)
@pytest.mark.skipif(
_target_python_version() < (3, 7), reason="Whool requires python3.7 or higher"
)
def test_import_odoo_after_addon_install():
with make_addons_dir(["addon_success"]) as addons_dir:
addon_dir = addons_dir / "addon_success"
subprocess.check_call(["git", "init"], cwd=addon_dir)
subprocess.check_call(["git", "add", "."], cwd=addon_dir)
subprocess.check_call(["git", "config", "user.email", "..."], cwd=addon_dir)
subprocess.check_call(
["git", "config", "user.name", "me@example.com"], cwd=addon_dir
)
subprocess.check_call(["git", "commit", "-m", "..."], cwd=addon_dir)
subprocess.check_call(
["python", "-m", "pip", "install", addons_dir / "addon_success"]
)
subprocess.check_call(["python", "-c", "import odoo.cli"])

13
tests/test_success.py Normal file
View File

@ -0,0 +1,13 @@
import subprocess
from .common import install_test_addons, dropdb, did_run_test_module
def test_success():
"""Basic successful test."""
with install_test_addons(["addon_success"]) as addons_dir:
dropdb()
subprocess.check_call(["oca_init_test_database"], cwd=addons_dir)
result = subprocess.check_output(
["oca_run_tests"], cwd=addons_dir, text=True
)
assert did_run_test_module(result, "addon_success.tests.test_success")