Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integration Test Optimizations #56

Merged
merged 8 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/unreleased/Features-20240131-152923.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
kind: Features
body: Cache static objects between tests to accelerate integration runs.
time: 2024-01-31T15:29:23.951857-05:00
custom:
Author: peterallenwebb
Issue: "55"
38 changes: 35 additions & 3 deletions dbt_common/clients/jinja.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import jinja2.parser # type: ignore
import jinja2.sandbox # type: ignore

from dbt_common.tests import test_caching_enabled
from dbt_common.utils.jinja import (
get_dbt_macro_name,
get_docs_macro_name,
Expand Down Expand Up @@ -504,9 +505,19 @@ def catch_jinja(node=None) -> Iterator[None]:
raise


_TESTING_PARSE_CACHE: Dict[str, jinja2.Template] = {}


def parse(string):
str_string = str(string)
if test_caching_enabled() and str_string in _TESTING_PARSE_CACHE:
return _TESTING_PARSE_CACHE[str_string]

with catch_jinja():
return get_environment().parse(str(string))
parsed = get_environment().parse(str(string))
if test_caching_enabled():
_TESTING_PARSE_CACHE[str_string] = parsed
return parsed


def get_template(
Expand All @@ -528,6 +539,15 @@ def render_template(template, ctx: Dict[str, Any], node=None) -> str:
return template.render(ctx)


_TESTING_BLOCKS_CACHE: Dict[int, List[Union[BlockData, BlockTag]]] = {}


def _get_blocks_hash(text: str, allowed_blocks: Optional[Set[str]], collect_raw_data: bool) -> int:
"""Provides a hash function over the arguments to extract_toplevel_blocks, in order to support caching."""
allowed_tuple = tuple(sorted(allowed_blocks) or [])
return text.__hash__() + allowed_tuple.__hash__() + collect_raw_data.__hash__()


def extract_toplevel_blocks(
text: str,
allowed_blocks: Optional[Set[str]] = None,
Expand All @@ -537,7 +557,7 @@ def extract_toplevel_blocks(

Includes some special handling for block nesting.

:param data: The data to extract blocks from.
:param text: The data to extract blocks from.
:param allowed_blocks: The names of the blocks to extract from the file.
They may not be nested within if/for blocks. If None, use the default
values.
Expand All @@ -548,7 +568,19 @@ def extract_toplevel_blocks(
:return: A list of `BlockTag`s matching the allowed block types and (if
`collect_raw_data` is `True`) `BlockData` objects.
"""

if test_caching_enabled():
hash = _get_blocks_hash(text, allowed_blocks, collect_raw_data)
if hash in _TESTING_BLOCKS_CACHE:
return _TESTING_BLOCKS_CACHE[hash]

tag_iterator = TagIterator(text)
return BlockIterator(tag_iterator).lex_for_blocks(
blocks = BlockIterator(tag_iterator).lex_for_blocks(
allowed_blocks=allowed_blocks, collect_raw_data=collect_raw_data
)

if test_caching_enabled():
hash = _get_blocks_hash(text, allowed_blocks, collect_raw_data)
_TESTING_BLOCKS_CACHE[hash] = blocks

return blocks
15 changes: 15 additions & 0 deletions dbt_common/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
_TEST_CACHING_ENABLED: bool = False


def test_caching_enabled() -> bool:
return _TEST_CACHING_ENABLED


def enable_test_caching() -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we add a disable_test_caching() method?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

global _TEST_CACHING_ENABLED
_TEST_CACHING_ENABLED = True


def disable_test_caching() -> None:
global _TEST_CACHING_ENABLED
_TEST_CACHING_ENABLED = False
Loading