187 lines
5.6 KiB
Python
187 lines
5.6 KiB
Python
from threading import Thread
|
|
|
|
from markupsafe import Markup
|
|
|
|
import jinjax
|
|
|
|
|
|
class ThreadWithReturnValue(Thread):
|
|
def __init__(self, group=None, target=None, name=None, args=None, kwargs=None):
|
|
args = args or ()
|
|
kwargs = kwargs or {}
|
|
Thread.__init__(
|
|
self,
|
|
group=group,
|
|
target=target,
|
|
name=name,
|
|
args=args,
|
|
kwargs=kwargs,
|
|
)
|
|
self._target = target
|
|
self._args = args
|
|
self._kwargs = kwargs
|
|
self._return = None
|
|
|
|
def run(self):
|
|
if self._target is not None:
|
|
self._return = self._target(*self._args, **self._kwargs)
|
|
|
|
def join(self, *args, **kwargs):
|
|
Thread.join(self, *args, **kwargs)
|
|
return self._return
|
|
|
|
|
|
def test_thread_safety_of_render_assets(catalog, folder):
|
|
NUM_THREADS = 5
|
|
|
|
child_tmpl = """
|
|
{#css "c{i}.css" #}
|
|
{#js "c{i}.js" #}
|
|
<p>Child {i}</p>""".strip()
|
|
|
|
parent_tmpl = """
|
|
{{ catalog.render_assets() }}
|
|
{{ content }}""".strip()
|
|
|
|
comp_tmpl = """
|
|
{#css "a{i}.css", "b{i}.css" #}
|
|
{#js "a{i}.js", "b{i}.js" #}
|
|
<Parent{i}><Child{i} /></Parent{i}>""".strip()
|
|
|
|
expected_tmpl = """
|
|
<link rel="stylesheet" href="/static/components/a{i}.css">
|
|
<link rel="stylesheet" href="/static/components/b{i}.css">
|
|
<link rel="stylesheet" href="/static/components/c{i}.css">
|
|
<script type="module" src="/static/components/a{i}.js"></script>
|
|
<script type="module" src="/static/components/b{i}.js"></script>
|
|
<script type="module" src="/static/components/c{i}.js"></script>
|
|
<p>Child {i}</p>""".strip()
|
|
|
|
def render(i):
|
|
return catalog.render(f"Page{i}")
|
|
|
|
for i in range(NUM_THREADS):
|
|
si = str(i)
|
|
child_name = f"Child{i}.jinja"
|
|
child_src = child_tmpl.replace("{i}", si)
|
|
|
|
parent_name = f"Parent{i}.jinja"
|
|
parent_src = parent_tmpl.replace("{i}", si)
|
|
|
|
comp_name = f"Page{i}.jinja"
|
|
comp_src = comp_tmpl.replace("{i}", si)
|
|
|
|
(folder / child_name).write_text(child_src)
|
|
(folder / comp_name).write_text(comp_src)
|
|
(folder / parent_name).write_text(parent_src)
|
|
|
|
threads = []
|
|
|
|
for i in range(NUM_THREADS):
|
|
thread = ThreadWithReturnValue(target=render, args=(i,))
|
|
threads.append(thread)
|
|
thread.start()
|
|
|
|
results = [thread.join() for thread in threads]
|
|
|
|
for i, result in enumerate(results):
|
|
expected = expected_tmpl.replace("{i}", str(i))
|
|
print(f"---- EXPECTED {i}----")
|
|
print(expected)
|
|
print(f"---- RESULT {i}----")
|
|
print(result)
|
|
assert result == Markup(expected)
|
|
|
|
|
|
def test_same_thread_assets_independence(catalog, folder):
|
|
catalog2 = jinjax.Catalog()
|
|
catalog2.add_folder(folder)
|
|
|
|
print("Catalog1 key:", catalog._key)
|
|
print("Catalog2 key:", catalog2._key)
|
|
|
|
# Check if the context variables exist before the test
|
|
print("Before any rendering:")
|
|
print("Catalog1 in collected_css:", catalog._key in jinjax.catalog.collected_css)
|
|
print("Catalog2 in collected_css:", catalog2._key in jinjax.catalog.collected_css)
|
|
print("collected_css keys:", list(jinjax.catalog.collected_css.keys()))
|
|
print("collected_js keys:", list(jinjax.catalog.collected_js.keys()))
|
|
|
|
(folder / "Parent.jinja").write_text(
|
|
"""
|
|
{{ catalog.render_assets() }}
|
|
{{ content }}""".strip()
|
|
)
|
|
|
|
(folder / "Comp1.jinja").write_text(
|
|
"""
|
|
{#css "a.css" #}
|
|
{#js "a.js" #}
|
|
<Parent />""".strip()
|
|
)
|
|
|
|
(folder / "Comp2.jinja").write_text(
|
|
"""
|
|
{#css "b.css" #}
|
|
{#js "b.js" #}
|
|
<Parent />""".strip()
|
|
)
|
|
|
|
expected_1 = """
|
|
<link rel="stylesheet" href="/static/components/a.css">
|
|
<script type="module" src="/static/components/a.js"></script>""".strip()
|
|
|
|
expected_2 = """
|
|
<link rel="stylesheet" href="/static/components/b.css">
|
|
<script type="module" src="/static/components/b.js"></script>""".strip()
|
|
|
|
# Render first component with first catalog
|
|
html1 = catalog.render("Comp1")
|
|
|
|
# Check context variables after first render
|
|
print("\nAfter first render:")
|
|
print("Catalog1 collected_css:", catalog.collected_css)
|
|
print("Catalog2 collected_css:", catalog2.collected_css)
|
|
print("Catalog1 in collected_css:", catalog._key in jinjax.catalog.collected_css)
|
|
print("Catalog2 in collected_css:", catalog2._key in jinjax.catalog.collected_css)
|
|
print("collected_css keys:", list(jinjax.catalog.collected_css.keys()))
|
|
|
|
# `irender` instead of `render` so the assets are not cleared
|
|
html2 = catalog2.irender("Comp2")
|
|
|
|
# Check context variables after second render
|
|
print("\nAfter second render:")
|
|
print("Catalog1 collected_css:", catalog.collected_css)
|
|
print("Catalog2 collected_css:", catalog2.collected_css)
|
|
print("Catalog1 in collected_css:", catalog._key in jinjax.catalog.collected_css)
|
|
print("Catalog2 in collected_css:", catalog2._key in jinjax.catalog.collected_css)
|
|
print("collected_css keys:", list(jinjax.catalog.collected_css.keys()))
|
|
|
|
print("\nHTML outputs:")
|
|
print("HTML1:", html1)
|
|
print("HTML2:", html2)
|
|
|
|
assert html1 == Markup(expected_1)
|
|
assert html2 == Markup(expected_2)
|
|
|
|
|
|
def test_thread_safety_of_template_globals(catalog, folder):
|
|
NUM_THREADS = 5
|
|
(folder / "Page.jinja").write_text(
|
|
"{{ globalvar if globalvar is defined else 'not set' }}"
|
|
)
|
|
|
|
def render(i):
|
|
return catalog.render("Page", _globals={"globalvar": i})
|
|
|
|
threads = []
|
|
|
|
for i in range(NUM_THREADS):
|
|
thread = ThreadWithReturnValue(target=render, args=(i,))
|
|
threads.append(thread)
|
|
thread.start()
|
|
|
|
results = [thread.join() for thread in threads]
|
|
|
|
for i, result in enumerate(results):
|
|
assert result == Markup(str(i))
|