Skip to content

Commit 4874995

Browse files
authored
test: increase TortoiseContext test coverage (#2138)
* Add tests for init context from config file * Add tests for init routers * Add tests for `set_global_context()`
1 parent 2183f86 commit 4874995

1 file changed

Lines changed: 193 additions & 0 deletions

File tree

tests/test_context.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,38 @@
88
by testing context isolation relative to the current state.
99
"""
1010

11+
import json
12+
1113
import pytest
14+
import yaml
1215

16+
from tortoise.config import AppConfig, DBUrlConfig, TortoiseConfig
1317
from tortoise.connection import ConnectionHandler
1418
from tortoise.context import (
1519
TortoiseContext,
1620
get_current_context,
1721
require_context,
22+
set_global_context,
1823
tortoise_test_context,
1924
)
2025
from tortoise.exceptions import ConfigurationError
2126

2227

28+
def _clear_global_context():
29+
"""Clear the global context to ensure test isolation."""
30+
import tortoise.context as ctx_module
31+
32+
ctx_module._global_context = None
33+
34+
35+
@pytest.fixture(autouse=True)
36+
def cleanup_global_context():
37+
"""Fixture to clear global context before and after each test."""
38+
_clear_global_context()
39+
yield
40+
_clear_global_context()
41+
42+
2343
class TestTortoiseContextInstantiation:
2444
"""Test cases for TortoiseContext instantiation."""
2545

@@ -198,6 +218,26 @@ async def test_apps_cleared_on_async_context_exit(self):
198218
assert ctx.apps is None
199219
assert ctx.inited is False
200220

221+
def test_set_global_context_sets_global(self):
222+
"""set_global_context sets the global context."""
223+
ctx = TortoiseContext()
224+
set_global_context(ctx)
225+
226+
# Verify global context is set
227+
import tortoise.context as ctx_module
228+
229+
assert ctx_module._global_context is ctx
230+
231+
def test_set_global_context_raises_when_already_set(self):
232+
"""set_global_context raises ConfigurationError when already set."""
233+
ctx1 = TortoiseContext()
234+
ctx2 = TortoiseContext()
235+
236+
set_global_context(ctx1)
237+
238+
with pytest.raises(ConfigurationError):
239+
set_global_context(ctx2)
240+
201241

202242
class TestGetModel:
203243
"""Test cases for get_model method."""
@@ -271,6 +311,64 @@ async def test_init_raises_with_invalid_config_no_apps(self):
271311

272312
assert 'Config must define "apps" section' in str(exc_info.value)
273313

314+
@pytest.mark.asyncio
315+
@pytest.mark.parametrize("serializer", [json.dumps, yaml.dump])
316+
async def test_init_with_config_file(self, tmp_path, serializer):
317+
"""init() with config_file (JSON/YAML) initializes context correctly."""
318+
suffix = ".yaml" if serializer is yaml.dump else ".json"
319+
config_file = tmp_path / f"config{suffix}"
320+
321+
config = TortoiseConfig(
322+
connections={"default": DBUrlConfig("sqlite://:memory:")},
323+
apps={"models": AppConfig(models=["tests.testmodels"])},
324+
)
325+
config_dict = config.to_dict()
326+
config_file.write_text(serializer(config_dict))
327+
328+
async with TortoiseContext() as ctx:
329+
await ctx.init(config_file=str(config_file))
330+
331+
assert ctx.inited is True
332+
assert ctx._connections is not None
333+
conn = ctx.connections.get("default")
334+
assert conn is not None
335+
assert ctx.apps is not None
336+
337+
@pytest.mark.asyncio
338+
async def test_init_raises_with_config_and_config_file(self, tmp_path):
339+
"""init() raises when both config and config_file are provided."""
340+
config = TortoiseConfig(
341+
connections={"default": DBUrlConfig("sqlite://:memory:")},
342+
apps={"models": AppConfig(models=["tests.testmodels"])},
343+
)
344+
config_dict = config.to_dict()
345+
346+
config_file = tmp_path / "config.json"
347+
config_file.write_text(json.dumps(config_dict))
348+
349+
ctx = TortoiseContext()
350+
351+
with pytest.raises(ConfigurationError) as exc_info:
352+
await ctx.init(
353+
config={"connections": {}, "apps": {}},
354+
config_file=str(config_file),
355+
)
356+
357+
assert "Cannot specify both 'config' and 'config_file'" in str(exc_info.value)
358+
359+
@pytest.mark.asyncio
360+
async def test_init_raises_with_invalid_config_file_extension(self, tmp_path):
361+
"""init() raises when config_file has unsupported extension."""
362+
config_file = tmp_path / "config.txt"
363+
config_file.write_text("some config")
364+
365+
ctx = TortoiseContext()
366+
367+
with pytest.raises(ConfigurationError) as exc_info:
368+
await ctx.init(config_file=str(config_file))
369+
370+
assert "Unknown config extension .txt" in str(exc_info.value)
371+
274372

275373
class TestGenerateSchemas:
276374
"""Test cases for generate_schemas method."""
@@ -467,6 +565,9 @@ async def test_sequential_contexts_isolated(self):
467565
class TestTimezoneAndRouters:
468566
"""Test cases for timezone and routers configuration."""
469567

568+
class TestRouter:
569+
pass
570+
470571
def test_context_default_timezone_settings(self):
471572
"""Context has default timezone settings."""
472573
ctx = TortoiseContext()
@@ -515,6 +616,98 @@ async def test_tortoise_test_context_with_timezone(self):
515616
assert ctx.use_tz is True
516617
assert ctx.timezone == "Asia/Tokyo"
517618

619+
@pytest.mark.asyncio
620+
async def test_init_routers_empty_list(self):
621+
"""_init_routers with empty list initializes correctly."""
622+
async with TortoiseContext() as ctx:
623+
await ctx.init(
624+
db_url="sqlite://:memory:",
625+
modules={"models": ["tests.testmodels"]},
626+
routers=[],
627+
)
628+
629+
assert ctx.routers == []
630+
631+
@pytest.mark.asyncio
632+
async def test_init_routers_with_type(self):
633+
"""_init_routers accepts router type directly."""
634+
635+
async with TortoiseContext() as ctx:
636+
await ctx.init(
637+
db_url="sqlite://:memory:",
638+
modules={"models": ["tests.testmodels"]},
639+
routers=[TestTimezoneAndRouters.TestRouter],
640+
)
641+
642+
assert ctx.routers == [TestTimezoneAndRouters.TestRouter]
643+
644+
@pytest.mark.asyncio
645+
async def test_init_routers_with_string_path(self):
646+
"""_init_routers accepts router as string path."""
647+
async with TortoiseContext() as ctx:
648+
await ctx.init(
649+
db_url="sqlite://:memory:",
650+
modules={"models": ["tests.testmodels"]},
651+
routers=["tortoise.router.ConnectionRouter"],
652+
)
653+
654+
from tortoise.router import ConnectionRouter
655+
656+
assert ctx.routers == [ConnectionRouter]
657+
658+
@pytest.mark.asyncio
659+
async def test_init_routers_mixed_types_and_strings(self):
660+
"""_init_routers accepts mixed router types and strings."""
661+
662+
async with TortoiseContext() as ctx:
663+
await ctx.init(
664+
db_url="sqlite://:memory:",
665+
modules={"models": ["tests.testmodels"]},
666+
routers=[TestTimezoneAndRouters.TestRouter, "tortoise.router.ConnectionRouter"],
667+
)
668+
669+
from tortoise.router import ConnectionRouter
670+
671+
assert ctx.routers == [TestTimezoneAndRouters.TestRouter, ConnectionRouter]
672+
673+
@pytest.mark.asyncio
674+
async def test_init_routers_invalid_router_type(self):
675+
"""_init_routers raises on invalid router type."""
676+
async with TortoiseContext() as ctx:
677+
with pytest.raises(ConfigurationError) as exc_info:
678+
await ctx.init(
679+
db_url="sqlite://:memory:",
680+
modules={"models": ["tests.testmodels"]},
681+
routers=["not_a_valid_router_path"],
682+
)
683+
684+
assert "Can't import router" in str(exc_info.value)
685+
686+
@pytest.mark.asyncio
687+
async def test_init_routers_invalid_router_item(self):
688+
"""_init_routers raises when router is neither string nor type."""
689+
async with TortoiseContext() as ctx:
690+
with pytest.raises(ConfigurationError) as exc_info:
691+
await ctx.init(
692+
db_url="sqlite://:memory:",
693+
modules={"models": ["tests.testmodels"]},
694+
routers=[123],
695+
)
696+
697+
assert "Router must be either str or type" in str(exc_info.value)
698+
699+
@pytest.mark.asyncio
700+
async def test_init_routers_none_uses_empty_list(self):
701+
"""_init_routers with None uses empty list."""
702+
async with TortoiseContext() as ctx:
703+
await ctx.init(
704+
db_url="sqlite://:memory:",
705+
modules={"models": ["tests.testmodels"]},
706+
routers=None,
707+
)
708+
709+
assert ctx.routers == []
710+
518711

519712
class TestTortoiseConfigValidation:
520713
"""Test cases for TortoiseConfig validation in ctx.init()."""

0 commit comments

Comments
 (0)