diff --git a/src/sqlbuild/cli/entry/constants.py b/src/sqlbuild/cli/entry/constants.py new file mode 100644 index 0000000000..6199328032 --- /dev/null +++ b/src/sqlbuild/cli/entry/constants.py @@ -0,0 +1,4 @@ +"""Stable constants for the CLI process entrypoint.""" + +NATIVE_ALLOCATOR_PURGE_DELAY_VARIABLE: str = "MIMALLOC_PURGE_DELAY" +NATIVE_ALLOCATOR_PURGE_DELAY_MILLISECONDS: str = "10" diff --git a/src/sqlbuild/cli/entry/main/entry.py b/src/sqlbuild/cli/entry/main/entry.py index 8de389d644..4e938aaae3 100644 --- a/src/sqlbuild/cli/entry/main/entry.py +++ b/src/sqlbuild/cli/entry/main/entry.py @@ -1,11 +1,20 @@ """Public SQLBuild CLI process entrypoint.""" +import os from collections.abc import Sequence -from sqlbuild.cli.commands.main.entrypoint.entry import main as _main +from sqlbuild.cli.entry.constants import ( + NATIVE_ALLOCATOR_PURGE_DELAY_MILLISECONDS, + NATIVE_ALLOCATOR_PURGE_DELAY_VARIABLE, +) def main(argv: Sequence[str] | None = None) -> int: """Run the SQLBuild CLI with optional explicit arguments.""" - return _main(argv) + os.environ.setdefault( + NATIVE_ALLOCATOR_PURGE_DELAY_VARIABLE, NATIVE_ALLOCATOR_PURGE_DELAY_MILLISECONDS + ) + from sqlbuild.cli.commands.main.entrypoint.entry import main as run_cli + + return run_cli(argv) diff --git a/tests/integration/src/sqlbuild/cli/commands/main/_test_types.py b/tests/integration/src/sqlbuild/cli/commands/main/_test_types.py index 7926643061..e3653daf72 100644 --- a/tests/integration/src/sqlbuild/cli/commands/main/_test_types.py +++ b/tests/integration/src/sqlbuild/cli/commands/main/_test_types.py @@ -809,3 +809,10 @@ class DiscoveryWorkTestCase: command: tuple[str, ...] expected_exit_code: int expected_eager_output_column_scans: int + + +@dataclass(frozen=True) +class NativeAllocatorEntryTestCase: + description: str + inherited_environment: tuple[tuple[str, str], ...] + expected_purge_delay: str diff --git a/tests/integration/src/sqlbuild/cli/commands/main/test_native_allocator_entry.py b/tests/integration/src/sqlbuild/cli/commands/main/test_native_allocator_entry.py new file mode 100644 index 0000000000..20c65d4a63 --- /dev/null +++ b/tests/integration/src/sqlbuild/cli/commands/main/test_native_allocator_entry.py @@ -0,0 +1,75 @@ +"""Fresh-process integration coverage for the native allocator entrypoint default.""" + +from __future__ import annotations + +import json +import os +import subprocess +import sys + +import pytest + +from tests.integration.src.sqlbuild.cli.commands.main._test_types import ( + NativeAllocatorEntryTestCase, +) + +_PURGE_DELAY_VARIABLE: str = "MIMALLOC_PURGE_DELAY" +_SCRIPT: str = """ +import json +import os +import sys +from sqlbuild.cli.entry.main.entry import main + +loaded_at_import = "sqlbuild._native" in sys.modules +exit_code = main(["--version"]) +print(json.dumps({ + "loaded_at_import": loaded_at_import, + "loaded_after_main": "sqlbuild._native" in sys.modules, + "purge_delay": os.environ.get("MIMALLOC_PURGE_DELAY"), + "exit_code": exit_code, +})) +""" + + +@pytest.mark.parametrize( + "test_case", + [ + NativeAllocatorEntryTestCase( + description="unset purge delay defaults to ten milliseconds", + inherited_environment=(), + expected_purge_delay="10", + ), + NativeAllocatorEntryTestCase( + description="user purge delay is preserved", + inherited_environment=((_PURGE_DELAY_VARIABLE, "250"),), + expected_purge_delay="250", + ), + ], + ids=lambda case: case.description, +) +def test_given_fresh_process_when_running_cli_entry_then_purge_delay_is_set_before_native_load( + test_case: NativeAllocatorEntryTestCase, +) -> None: + environment: dict[str, str] = os.environ.copy() + environment.pop(_PURGE_DELAY_VARIABLE, None) + environment.update(test_case.inherited_environment) + + result: subprocess.CompletedProcess[str] = subprocess.run( + [sys.executable, "-c", _SCRIPT], + check=True, + capture_output=True, + env=environment, + text=True, + ) + payload: dict[str, object] = json.loads(result.stdout.strip().splitlines()[-1]) + + assert payload == { + "loaded_at_import": False, + "loaded_after_main": True, + "purge_delay": test_case.expected_purge_delay, + "exit_code": 0, + } + + +if __name__ == "__main__": + pytest.main([__file__, "-vv"])