test_snapshot_dir fixture with marker file for finished snapshot

This commit is contained in:
Christian Schwarz
2024-01-05 13:41:12 +00:00
parent 72da46dd5a
commit 838a6d304d
2 changed files with 54 additions and 10 deletions

View File

@@ -3268,8 +3268,8 @@ def get_test_output_dir(request: FixtureRequest, top_output_dir: Path) -> Path:
def get_test_overlay_dir(request: FixtureRequest, top_output_dir: Path) -> Path:
return _get_test_dir(request, top_output_dir, "overlay-")
def get_test_snapshot_dir(request: FixtureRequest, top_output_dir: Path) -> Path:
return _get_test_dir(request, top_output_dir, "snapshot")
def get_test_snapshot_dir_path(request: FixtureRequest, top_output_dir: Path) -> Path:
return _get_test_dir(request, top_output_dir, "snapshot-")
def get_test_repo_dir(request: FixtureRequest, top_output_dir: Path) -> Path:
return get_test_output_dir(request, top_output_dir) / "repo"
@@ -3314,6 +3314,44 @@ def test_output_dir(request: FixtureRequest, top_output_dir: Path, test_overlay_
allure_attach_from_dir(test_dir)
class SnapshotDir:
_path: Path
def __init__(self, path: Path):
self._path = path
if not self._path.exists():
self._path.mkdir()
else:
assert self._path.is_dir()
@property
def path(self) -> Path:
return self._path / "snapshot"
@property
def _marker_file_path(self) -> Path:
return self._path / "initialized.marker"
def is_initialized(self):
# TODO: in the future, take a `tag` as argument and store it in the marker in set_initialized.
# Then, in this function, compare marker file contents with the tag to invalidate the snapshot if the tag changed.
return self._marker_file_path.exists()
def set_initialized(self):
self._marker_file_path.write_text("")
@pytest.fixture(scope="function", autouse=True)
def test_snapshot_dir(request: FixtureRequest, top_output_dir: Path, test_overlay_dir: Path) -> SnapshotDir:
"""Create the working directory for an individual test."""
_ = test_overlay_dir # overlay mounts use snapshot dir as the lowerdir => request it so it can unmount stale overlay mounts first
# one directory per test
snapshot_dir = get_test_snapshot_dir_path(request, top_output_dir)
log.info(f"test_snapshot_dir is {snapshot_dir}")
return SnapshotDir(snapshot_dir)
@pytest.fixture(scope="function", autouse=True)
def test_overlay_dir(request: FixtureRequest, top_output_dir: Path) -> Optional[Path]:
"""Create the overlay state directory for an individual test."""

View File

@@ -8,7 +8,7 @@ from typing import List, Tuple
import pytest
from fixtures.benchmark_fixture import NeonBenchmarker
from fixtures.log_helper import log
from fixtures.neon_fixtures import NeonEnv, NeonEnvBuilder, PgBin, last_flush_lsn_upload
from fixtures.neon_fixtures import NeonEnv, NeonEnvBuilder, PgBin, SnapshotDir, last_flush_lsn_upload
from fixtures.pageserver.utils import wait_until_tenant_active
from fixtures.remote_storage import LocalFsStorage, RemoteStorageKind
from fixtures.types import TenantId, TimelineId
@@ -17,7 +17,9 @@ from fixtures.types import TenantId, TimelineId
@pytest.fixture(scope="function")
@pytest.mark.timeout(1000)
def snapshotting_env(
neon_env_builder: NeonEnvBuilder, pg_bin: PgBin, test_output_dir: Path,
neon_env_builder: NeonEnvBuilder,
pg_bin: PgBin,
test_snapshot_dir: SnapshotDir,
) -> Tuple[NeonEnv, TimelineId, List[TenantId]]:
"""
The fixture prepares environment or restores it from a snapshot.
@@ -28,7 +30,6 @@ def snapshotting_env(
- if the fixture is executed on CI (it has CI=true in the environment), the snapshot is not saved
"""
snapshot_dir = test_output_dir.parent / f"snapshot-{test_output_dir.name}"
save_snapshot = os.getenv("CI", "false") != "true"
neon_env_builder.enable_pageserver_remote_storage(RemoteStorageKind.LOCAL_FS)
@@ -44,10 +45,14 @@ def snapshotting_env(
"image_creation_threshold": 3,
}
if snapshot_dir.exists():
env = neon_env_builder.from_repo_dir(snapshot_dir)
if test_snapshot_dir.is_initialized():
save_snapshot = False
env = neon_env_builder.from_repo_dir(test_snapshot_dir.path)
ps_http = env.pageserver.http_client()
tenants = list({TenantId(t.name) for t in (snapshot_dir.glob("pageserver_*/tenants/*"))})
tenants = list(
{TenantId(t.name) for t in (test_snapshot_dir.path.glob("pageserver_*/tenants/*"))}
)
template_timeline = env.initial_timeline
neon_env_builder.start()
@@ -128,8 +133,9 @@ def snapshotting_env(
ps_http.download_all_layers(tenant, template_timeline)
# take snapshot after download all layers so tenant dir restoration is fast
if save_snapshot and not snapshot_dir.exists():
shutil.copytree(env.repo_dir, snapshot_dir)
if save_snapshot:
shutil.copytree(env.repo_dir, test_snapshot_dir.path)
test_snapshot_dir.set_initialized()
return env, template_timeline, tenants