Skip to content

Commit

Permalink
integrate zope.test browser, clean warnings
Browse files Browse the repository at this point in the history
Re ARAMAKI-7
  • Loading branch information
ctheune committed Feb 12, 2024
1 parent 52842c2 commit af9ef7b
Show file tree
Hide file tree
Showing 15 changed files with 663 additions and 154 deletions.
203 changes: 148 additions & 55 deletions poetry.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pytest-cache = ">=1.0"
pytest-timeout = ">=2.2"
pytest-mypy = ">=0.10"
pytest-patterns = ">=0.1"
"zope.testbrowser" = ">=6.0"

[tool.poetry.plugins."paste.app_factory"]
main = "aramaki.server.web.main:main"
Expand Down Expand Up @@ -97,3 +98,7 @@ ignore_errors = true
[[tool.mypy.overrides]]
module = "webtest.*"
ignore_errors = true

[[tool.mypy.overrides]]
module = "pyramid.testing.*"
ignore_missing_imports = true
7 changes: 6 additions & 1 deletion pytest.ini
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
[pytest]
addopts = --timeout=60 --mypy --cov=src --cov-report=html --cov-report=term --ignore lib --ignore lib64 --strict-markers
addopts = --timeout=60 --mypy --cov=src --cov-report=html --cov-report=term --ignore lib --ignore lib64 --strict-markers -vv
testpaths = src/aramaki

filterwarnings =
ignore::DeprecationWarning:pkg_resources.*:
ignore::DeprecationWarning:webob.*:
ignore::DeprecationWarning:pyramid.*:
102 changes: 13 additions & 89 deletions src/aramaki/server/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
import alembic.config
import pytest
import transaction
import webtest
import zope.testbrowser.wsgi
from pyramid.paster import get_appsettings
from pyramid.scripting import prepare
from pyramid.testing import DummyRequest, testConfig

from aramaki.server import models
from aramaki.server.models.meta import Base
Expand All @@ -30,112 +28,38 @@ def app_settings(ini_file):
return get_appsettings(ini_file)


@pytest.fixture(scope="session")
@pytest.fixture
def dbengine(app_settings, ini_file):
engine = models.get_engine(app_settings)

alembic_cfg = alembic.config.Config(ini_file)
Base.metadata.drop_all(bind=engine)
alembic.command.stamp(alembic_cfg, None, purge=True)
# https://github.com/sqlalchemy/alembic/issues/1420
alembic.command.stamp(alembic_cfg, None, purge=True) # type: ignore

alembic.command.upgrade(alembic_cfg, "head")

yield engine

Base.metadata.drop_all(bind=engine)
alembic.command.stamp(alembic_cfg, None, purge=True)


@pytest.fixture(scope="session")
@pytest.fixture
def app(app_settings, dbengine):
return main({}, dbengine=dbengine, **app_settings)


@pytest.fixture
def tm():
tm = transaction.TransactionManager(explicit=True)
tm.begin()
tm.doom()

yield tm

tm.abort()


@pytest.fixture
def dbsession(app, tm):
def dbsession(app):
session_factory = app.registry["dbsession_factory"]
return models.get_tm_session(session_factory, tm)


@pytest.fixture
def testapp(app, tm, dbsession):
# override request.dbsession and request.tm with our own
# externally-controlled values that are shared across requests but aborted
# at the end
testapp = webtest.TestApp(
app,
extra_environ={
"HTTP_HOST": "example.com",
"tm.active": True,
"tm.manager": tm,
"app.dbsession": dbsession,
},
)

return testapp


@pytest.fixture
def app_request(app, tm, dbsession):
"""
A real request.
This request is almost identical to a real request but it has some
drawbacks in tests as it's harder to mock data and is heavier.
"""
with prepare(registry=app.registry) as env:
request = env["request"]
request.host = "example.com"

# without this, request.dbsession will be joined to the same
# transaction manager but it will be using a different
# sqlalchemy.orm.Session using a separate database transaction
request.dbsession = dbsession
request.tm = tm

yield request
with transaction.manager:
yield models.get_tm_session(session_factory, transaction.manager)


@pytest.fixture
def dummy_request(tm, dbsession):
"""
A lightweight dummy request.
def testbrowser(app):
"""A fully functional testbrowser stack.
This request is ultra-lightweight and should be used only when the request
itself is not a large focus in the call-stack. It is much easier to mock
and control side-effects using this object, however:
- It does not have request extensions applied.
- Threadlocals are not properly pushed.
"""
request = DummyRequest()
request.host = "example.com"
request.dbsession = dbsession
request.tm = tm

return request


@pytest.fixture
def dummy_config(dummy_request):
"""
A dummy :class:`pyramid.config.Configurator` object. This allows for
mock configuration, including configuration for ``dummy_request``, as well
as pushing the appropriate threadlocals.
This uses a fully functional database integration and thus requires
test database support to replace the database cleanly after each test.
"""
with testConfig(request=dummy_request) as config:
yield config
return zope.testbrowser.wsgi.Browser(wsgi_app=app)
28 changes: 21 additions & 7 deletions src/aramaki/server/tests/test_system.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import uuid

import pytest_patterns.plugin
import transaction

from aramaki.server.models.system import Instance, System, SystemCategory

Expand Down Expand Up @@ -44,7 +45,7 @@ def test_system_basic():


def test_system_overview(
testapp, dbsession, patterns: pytest_patterns.plugin.PatternsLib
testbrowser, dbsession, patterns: pytest_patterns.plugin.PatternsLib
):
instance = Instance()
infrastructure = SystemCategory("Infrastructure")
Expand Down Expand Up @@ -97,9 +98,18 @@ def test_system_overview(

dbsession.flush()

res = testapp.get("/", status=200)
transaction.commit()

testbrowser.open("http://example.com/")

owrap = patterns.owrap
owrap.optional("<empty-line>")
owrap.optional(" ")
owrap.optional(" ")
owrap.optional(" <meta ...>")
owrap.optional(" <script ...>")
owrap.optional(" <link ...>")
owrap.optional(" <!-- ...")
owrap.in_order(
"""
<!DOCTYPE html>
Expand All @@ -108,6 +118,9 @@ def test_system_overview(
<title>Aramaki</title>
</head>
<body ...>
<nav ...>
Aramaki
</nav>
<div ...>
</div>
</body>
Expand All @@ -123,20 +136,21 @@ def test_system_overview(
<h2 ...>Infrastructure</h2>
<ul ...>
<li>First data center</li>
<li>First data center</li>
<li>Second data center</li>
</ul>
</div>
<div>
<h2 ...>Project</h2>
<empty-line>
<ul ...>
<li>First project</li>
<li>Second project</li>
</ul>
</div>
<div>
<h2 ...>Services</h2>
<empty-line>
<h2 ...>Service</h2>
<ul ...>
<li>First service</li>
<li>Second service</li>
Expand All @@ -145,4 +159,4 @@ def test_system_overview(
"""
)

assert dashboard == res.ubody
assert dashboard == testbrowser.contents
2 changes: 1 addition & 1 deletion src/aramaki/server/web/static/aramaki.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/aramaki/server/web/templates/layout.pt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
</nav>

<div class="fixed h-screen w-72 bg-fc-midnight pt-4 text-white">

<div tal:repeat="category request.api.navigation()">
<h2 class="bg-fc-midnight-500 p-4">${category.title}</h2>

Expand Down
Empty file.
Loading

0 comments on commit af9ef7b

Please sign in to comment.