mirror of
https://github.com/neondatabase/neon.git
synced 2026-05-27 18:10:37 +00:00
test_snapshot_dir fixture with marker file for finished snapshot
This commit is contained in:
@@ -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."""
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user