From 75ba860ba2d32ace55037712f16ba07439055f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Andrei?= Date: Mon, 13 Jul 2026 23:23:32 -0300 Subject: [PATCH] Upgrade pytest-plone to 1.1.0 Bump pytest-plone to >=1.1.0. The new keep_session=True default keeps all registered layer sessions pinned at once, which exposed a duplicate Plone site collision: the acceptance layer pulled in the stock PLONE_FIXTURE (via plone.app.robotframework's REMOTE_LIBRARY_BUNDLE_FIXTURE), whose default setUpDefaultContent creates a site with id "plone" -- the same id our CoreFixture already creates. Re-parent a locally-built remote-library bundle onto kitconcept_FIXTURE (new testing/robot.py holding RF_LIBRARIES) so the stock PLONE_FIXTURE is no longer in the base chain. Also rename the distribution fixture to distribution_name and make create_site idempotent. GitLab: https://gitlab.kitconcept.io/kitconcept/distribution-kitconcept-intranet/-/issues/462 --- backend/news/462.tests | 1 + backend/pyproject.toml | 4 ++-- .../src/kitconcept/core/testing/__init__.py | 8 ++++++- backend/src/kitconcept/core/testing/layers.py | 2 +- backend/src/kitconcept/core/testing/robot.py | 20 +++++++++++++++++ backend/tests/conftest.py | 22 ++++++++++++------- backend/tests/creation/conftest.py | 6 ++--- backend/tests/services/sites/test_sites.py | 13 +++++++---- backend/uv.lock | 12 +++++----- 9 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 backend/news/462.tests create mode 100644 backend/src/kitconcept/core/testing/robot.py diff --git a/backend/news/462.tests b/backend/news/462.tests new file mode 100644 index 00000000..63d30260 --- /dev/null +++ b/backend/news/462.tests @@ -0,0 +1 @@ +Upgrade `pytest-plone` to version 1.1.0 and re-parent the acceptance remote-library bundle onto the kitconcept fixture, avoiding a duplicate Plone site under the new `keep_session` default. @ericof diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 782de805..3fe40aa1 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -45,7 +45,7 @@ test = [ "plone.restapi[test]", "pytest", "pytest-cov", - "pytest-plone>=1.0.0", + "pytest-plone>=1.1.0", ] [dependency-groups] @@ -59,7 +59,7 @@ test = [ "plone.restapi[test]", "pytest", "pytest-cov", - "pytest-plone>=1.0.0", + "pytest-plone>=1.1.0", ] [project.urls] diff --git a/backend/src/kitconcept/core/testing/__init__.py b/backend/src/kitconcept/core/testing/__init__.py index 2cb9a8df..2b2e35a9 100644 --- a/backend/src/kitconcept/core/testing/__init__.py +++ b/backend/src/kitconcept/core/testing/__init__.py @@ -1,5 +1,6 @@ from kitconcept.core.testing import layers -from plone.app.robotframework.testing import REMOTE_LIBRARY_BUNDLE_FIXTURE +from kitconcept.core.testing import robot +from plone.app.robotframework.remote import RemoteLibraryLayer from plone.app.testing import FunctionalTesting from plone.app.testing import IntegrationTesting from plone.app.testing import PloneSandboxLayer @@ -26,6 +27,11 @@ class Layer(PloneSandboxLayer): name="kitconcept.coreLayer:FunctionalTesting", ) +REMOTE_LIBRARY_BUNDLE_FIXTURE = RemoteLibraryLayer( + bases=(kitconcept_FIXTURE,), + libraries=robot.RF_LIBRARIES, + name="RemoteLibraryBundle:RobotRemote", +) ACCEPTANCE_TESTING = FunctionalTesting( bases=( diff --git a/backend/src/kitconcept/core/testing/layers.py b/backend/src/kitconcept/core/testing/layers.py index dc4fe6e7..7266ea89 100644 --- a/backend/src/kitconcept/core/testing/layers.py +++ b/backend/src/kitconcept/core/testing/layers.py @@ -58,6 +58,7 @@ def setUpDefaultContent(self, app): sites = self.sites if not sites: raise RuntimeError("No sites defined in this fixture") + for distribution_name, answers in sites: site_id = answers["site_id"] # Create Plone site @@ -67,7 +68,6 @@ def setUpDefaultContent(self, app): distribution=distribution_name, **answers, ) - # Create the test user. (Plone)PAS does not have an API to create a # user with different userid and login name, so we call the plugin # directly. diff --git a/backend/src/kitconcept/core/testing/robot.py b/backend/src/kitconcept/core/testing/robot.py new file mode 100644 index 00000000..372a0907 --- /dev/null +++ b/backend/src/kitconcept/core/testing/robot.py @@ -0,0 +1,20 @@ +from plone.app.robotframework.autologin import AutoLogin +from plone.app.robotframework.content import Content +from plone.app.robotframework.genericsetup import GenericSetup +from plone.app.robotframework.i18n import I18N +from plone.app.robotframework.mailhost import MockMailHost +from plone.app.robotframework.quickinstaller import QuickInstaller +from plone.app.robotframework.server import Zope2ServerRemote +from plone.app.robotframework.users import Users + + +RF_LIBRARIES = ( + AutoLogin, + QuickInstaller, + GenericSetup, + Content, + Users, + I18N, + MockMailHost, + Zope2ServerRemote, +) diff --git a/backend/tests/conftest.py b/backend/tests/conftest.py index c2a634d4..f28bdcc1 100644 --- a/backend/tests/conftest.py +++ b/backend/tests/conftest.py @@ -16,11 +16,14 @@ globals().update( - fixtures_factory(( - (ACCEPTANCE_TESTING, "acceptance"), - (FUNCTIONAL_TESTING, "functional"), - (INTEGRATION_TESTING, "integration"), - )) + fixtures_factory( + ( + (ACCEPTANCE_TESTING, "acceptance"), + (FUNCTIONAL_TESTING, "functional"), + (INTEGRATION_TESTING, "integration"), + ), + keep_session=True, + ) ) @@ -74,7 +77,7 @@ def current_versions() -> CurrentVersions: @pytest.fixture(scope="session") -def distribution() -> str: +def distribution_name() -> str: return "testing" @@ -101,10 +104,13 @@ def answers(prepare_answers) -> dict: @pytest.fixture(scope="session") -def create_site(distribution): +def create_site(distribution_name): def func(app, answers: dict) -> PloneSite: with api.env.adopt_user(SITE_OWNER_NAME): - site = add_site(app, distribution=distribution, **answers) + site_id = answers.get("site_id") + if site_id and (site_id in app.objectIds()): + app.manage_delObjects(site_id) + site = add_site(app, distribution=distribution_name, **answers) return site return func diff --git a/backend/tests/creation/conftest.py b/backend/tests/creation/conftest.py index 9dd7b98a..048559ae 100644 --- a/backend/tests/creation/conftest.py +++ b/backend/tests/creation/conftest.py @@ -1,4 +1,3 @@ -from Acquisition import aq_parent from collections.abc import Generator from Products.CMFPlone.Portal import PloneSite @@ -6,7 +5,6 @@ @pytest.fixture(scope="class") -def portal(portal_class, create_site, answers) -> Generator[PloneSite, None, None]: - app = aq_parent(portal_class) - site = create_site(app=app, answers=answers) +def portal(app_class, create_site, answers) -> Generator[PloneSite, None, None]: + site = create_site(app=app_class, answers=answers) yield site diff --git a/backend/tests/services/sites/test_sites.py b/backend/tests/services/sites/test_sites.py index a58f8384..90ee5ce3 100644 --- a/backend/tests/services/sites/test_sites.py +++ b/backend/tests/services/sites/test_sites.py @@ -1,11 +1,14 @@ +from copy import deepcopy +from random import randint + import pytest class TestSitesEndpoint: @pytest.fixture(autouse=True) - def _setup(self, api_manager_request, distribution): + def _setup(self, api_manager_request, distribution_name): self.api_session = api_manager_request - self.url = f"@sites/{distribution}" + self.url = f"@sites/{distribution_name}" def test_get(self): response = self.api_session.get(self.url) @@ -34,9 +37,11 @@ def test_get_add_definitions(self, key: str): assert key in definitions def test_post(self, answers): - response = self.api_session.post(self.url, json=answers) + _answers = deepcopy(answers) + _answers["site_id"] = f"plone{randint(5, 10):02d}" # noqa: S311 + response = self.api_session.post(self.url, json=_answers) data = response.json() assert response.status_code == 200 assert isinstance(data, dict) - assert data["id"] == answers["site_id"] + assert data["id"] == _answers["site_id"] assert data["_profile_id"] == "kitconcept.core:base" diff --git a/backend/uv.lock b/backend/uv.lock index 391e9ad8..b079ebed 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -1404,7 +1404,7 @@ requires-dist = [ { name = "products-cmfplone", specifier = "==6.2.1" }, { name = "pytest", marker = "extra == 'test'" }, { name = "pytest-cov", marker = "extra == 'test'" }, - { name = "pytest-plone", marker = "extra == 'test'", specifier = ">=1.0.0" }, + { name = "pytest-plone", marker = "extra == 'test'", specifier = ">=1.1.0" }, ] provides-extras = ["test"] @@ -1419,7 +1419,7 @@ test = [ { name = "plone-restapi", extras = ["test"] }, { name = "pytest" }, { name = "pytest-cov" }, - { name = "pytest-plone", specifier = ">=1.0.0" }, + { name = "pytest-plone", specifier = ">=1.1.0" }, ] [[package]] @@ -4718,7 +4718,7 @@ wheels = [ [[package]] name = "pytest-plone" -version = "1.0.0" +version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "plone-api" }, @@ -4726,6 +4726,8 @@ dependencies = [ { name = "plone-base" }, { name = "plone-browserlayer" }, { name = "plone-dexterity" }, + { name = "plone-distribution" }, + { name = "plone-exportimport" }, { name = "products-cmfplone", extra = ["test"] }, { name = "pytest" }, { name = "requests" }, @@ -4733,9 +4735,9 @@ dependencies = [ { name = "zope-pytestlayer" }, { name = "zope-schema" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/57/3b6cac92b5554e1c7f124dcb2b8cf25bc3de63668d264fee2c43ab4240ca/pytest_plone-1.0.0.tar.gz", hash = "sha256:3c60b893edc9a1dadf2a21b090b1ca389a2787dc754105ee7b6b35721361a822", size = 28120, upload-time = "2026-05-18T22:12:42.902Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/9e/51694db94e142b545835d3070d213a631d29387a62a1f5fec5a00c5c237e/pytest_plone-1.1.0.tar.gz", hash = "sha256:9f3ac2e4f975dddf9c773f176de2114467d624016250bef01f8763a2d482dcf2", size = 67794, upload-time = "2026-07-13T22:17:11.462Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/a8/01780c4ded556b57e617e88e0cd0c2eb11c6f41f0f27aec3d5b3e4c1885d/pytest_plone-1.0.0-py3-none-any.whl", hash = "sha256:51533c8df40947fcf7eae865483bae6e7ac4b94481c55724846cdd86868ef058", size = 23434, upload-time = "2026-05-18T22:12:41.303Z" }, + { url = "https://files.pythonhosted.org/packages/7b/a3/c32e1cc815f32b5ecd4bc8c1329f7490f35f59bf390d6eeb2a8c27610bc4/pytest_plone-1.1.0-py3-none-any.whl", hash = "sha256:89f69669ecb45f77ae3517238922f2c8a7e6eccd14dac8acd831f52a4fb4caf0", size = 30432, upload-time = "2026-07-13T22:17:10.107Z" }, ] [[package]]