userver: /data/code/userver/testsuite/pytest_plugins/pytest_userver/plugins/sql_coverage.py Source File
Loading...
Searching...
No Matches
sql_coverage.py
1"""
2Plugin that imports the required fixtures for checking SQL/YQL coverage. See
3@ref sql_coverage_test_info "SQL coverage tests" for more info.
4
5@ingroup userver_testsuite_fixtures
6"""
7
8from collections.abc import Iterable
9from collections.abc import Sequence
10
11import pytest
12
14
15pytest_plugins = ['pytest_userver.plugins.generated_tests']
16
17
18@pytest.fixture
20 """
21 Called when the coverage is incomplete.
22
23 Override this fixture to change the way uncovered statements are reported or to ignore some of the statements
24 from coverage report.
25
26 See @ref sql_coverage_test_info "SQL coverage tests" for more info.
27
28 @ingroup userver_testsuite_fixtures
29 """
30
31 def _on_uncovered(uncovered_statements: set[str]):
32 msg = f'Uncovered SQL/YQL statements: {uncovered_statements}'
34
35 return _on_uncovered
36
37
39 """
40 Contains data about the current coverage of statements.
41 """
42
43 def __init__(self, files: set[str]):
44 self.covered_statements: set[str] = set()
45 self.uncovered_statements: set[str] = files
46 self.extra_covered_statements: set[str] = set()
47
48 def cover(self, statement: str) -> None:
49 if statement in self.uncovered_statements:
50 self.covered_statements.add(statement)
51 self.uncovered_statements.remove(statement)
52 elif statement not in self.covered_statements:
53 self.extra_covered_statements.add(statement)
54
55 def validate(self, uncovered_callback: callable) -> None:
57 uncovered_callback(self.uncovered_statements)
58
59
60@pytest.fixture(scope='session')
61def sql_coverage(sql_files) -> Coverage:
62 """
63 Returns data about the current coverage of statements.
64
65 See @ref sql_coverage_test_info "SQL coverage tests" for more info.
66
67 @ingroup userver_testsuite_fixtures
68 """
69 return Coverage(set(sql_files))
70
71
72@pytest.fixture(autouse=True)
73def sql_statement_hook(testpoint, sql_coverage):
74 """
75 Hook that accepts requests from the testpoint with information on PostgreSQL statements coverage.
76
77 See @ref sql_coverage_test_info "SQL coverage tests" for more info.
78
79 @ingroup userver_testsuite_fixtures
80 """
81
82 @testpoint('sql_statement')
83 def _hook(request):
84 sql_coverage.cover(request['name'])
85
86 return _hook
87
88
89@pytest.fixture(autouse=True)
90async def yql_statement_hook(testpoint, sql_coverage):
91 """
92 Hook that accepts requests from the testpoint with information on YDB statements coverage.
93
94 See @ref sql_coverage_test_info "SQL coverage tests" for more info.
95
96 @ingroup userver_testsuite_fixtures
97 """
98
99 @testpoint('yql_statement')
100 def _hook(request):
101 sql_coverage.cover(request['name'])
102
103 return _hook
104
105
106def test_sql_coverage(sql_coverage, on_uncovered):
107 sql_coverage.validate(on_uncovered)
108
109
110def pytest_generate_virtual_tests(
111 parent: pytest.File,
112 config: pytest.Config,
113 existing_items: Sequence[pytest.Item],
114) -> Iterable[pytest.Item]:
115 if config.pluginmanager.hasplugin('sql_files'):
116 yield pytest.Function.from_parent(
117 parent=parent,
118 name=test_sql_coverage.__name__,
119 callobj=test_sql_coverage,
120 )
121
122
123@pytest.hookimpl(wrapper=True)
124def pytest_collection_modifyitems(config: pytest.Config, items: list[pytest.Item]) -> None:
125 yield
126 if items:
127 pytest_userver.utils.coverage.collection_modifyitems(test_sql_coverage.__name__, config, items)