From 9211923bef11da53421ca5949c558cfec13c7f61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s?= Date: Thu, 20 Oct 2022 09:46:57 +0200 Subject: [PATCH] Pageserver Python tests should not fail if the server is built with no testing feature (#2636) Co-authored-by: andres --- test_runner/fixtures/neon_fixtures.py | 60 ++++++++++--------- test_runner/performance/test_perf_pgbench.py | 5 +- test_runner/regress/test_recovery.py | 7 +-- test_runner/regress/test_tenant_relocation.py | 6 +- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/test_runner/fixtures/neon_fixtures.py b/test_runner/fixtures/neon_fixtures.py index 88910d2bdf..c6bfa7f69e 100644 --- a/test_runner/fixtures/neon_fixtures.py +++ b/test_runner/fixtures/neon_fixtures.py @@ -149,19 +149,6 @@ def pytest_configure(config): raise Exception('neon binaries not found at "{}"'.format(neon_binpath)) -def profiling_supported(): - """Return True if the pageserver was compiled with the 'profiling' feature""" - bin_pageserver = os.path.join(str(neon_binpath), "pageserver") - res = subprocess.run( - [bin_pageserver, "--version"], - check=True, - universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - return "profiling:true" in res.stdout - - def shareable_scope(fixture_name, config) -> Literal["session", "function"]: """Return either session of function scope, depending on TEST_SHARED_FIXTURES envvar. @@ -874,6 +861,17 @@ class NeonEnv: """Get a timeline directory's path based on the repo directory of the test environment""" return self.repo_dir / "tenants" / str(tenant_id) / "timelines" / str(timeline_id) + def get_pageserver_version(self) -> str: + bin_pageserver = os.path.join(str(neon_binpath), "pageserver") + res = subprocess.run( + [bin_pageserver, "--version"], + check=True, + universal_newlines=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + return res.stdout + @cached_property def auth_keys(self) -> AuthKeys: pub = (Path(self.repo_dir) / "auth_public_key.pem").read_bytes() @@ -972,10 +970,11 @@ class NeonPageserverApiException(Exception): class NeonPageserverHttpClient(requests.Session): - def __init__(self, port: int, auth_token: Optional[str] = None): + def __init__(self, port: int, is_testing_enabled_or_skip, auth_token: Optional[str] = None): super().__init__() self.port = port self.auth_token = auth_token + self.is_testing_enabled_or_skip = is_testing_enabled_or_skip if auth_token is not None: self.headers["Authorization"] = f"Bearer {auth_token}" @@ -994,6 +993,8 @@ class NeonPageserverHttpClient(requests.Session): self.get(f"http://localhost:{self.port}/v1/status").raise_for_status() def configure_failpoints(self, config_strings: tuple[str, str] | list[tuple[str, str]]) -> None: + self.is_testing_enabled_or_skip() + if isinstance(config_strings, tuple): pairs = [config_strings] else: @@ -1111,6 +1112,8 @@ class NeonPageserverHttpClient(requests.Session): def timeline_gc( self, tenant_id: TenantId, timeline_id: TimelineId, gc_horizon: Optional[int] ) -> dict[str, Any]: + self.is_testing_enabled_or_skip() + log.info( f"Requesting GC: tenant {tenant_id}, timeline {timeline_id}, gc_horizon {repr(gc_horizon)}" ) @@ -1126,6 +1129,8 @@ class NeonPageserverHttpClient(requests.Session): return res_json def timeline_compact(self, tenant_id: TenantId, timeline_id: TimelineId): + self.is_testing_enabled_or_skip() + log.info(f"Requesting compact: tenant {tenant_id}, timeline {timeline_id}") res = self.put( f"http://localhost:{self.port}/v1/tenant/{tenant_id}/timeline/{timeline_id}/compact" @@ -1150,6 +1155,8 @@ class NeonPageserverHttpClient(requests.Session): return res_json def timeline_checkpoint(self, tenant_id: TenantId, timeline_id: TimelineId): + self.is_testing_enabled_or_skip() + log.info(f"Requesting checkpoint: tenant {tenant_id}, timeline {timeline_id}") res = self.put( f"http://localhost:{self.port}/v1/tenant/{tenant_id}/timeline/{timeline_id}/checkpoint" @@ -1469,21 +1476,6 @@ class NeonCli(AbstractNeonCli): res.check_returncode() return res - def pageserver_enabled_features(self) -> Any: - bin_pageserver = os.path.join(str(neon_binpath), "pageserver") - args = [bin_pageserver, "--enabled-features"] - log.info('Running command "{}"'.format(" ".join(args))) - - res = subprocess.run( - args, - check=True, - universal_newlines=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - ) - log.info(f"pageserver_enabled_features success: {res.stdout}") - return json.loads(res.stdout) - def pageserver_start( self, overrides=(), @@ -1642,6 +1634,7 @@ class NeonPageserver(PgProtocol): self.running = False self.service_port = port self.config_override = config_override + self.version = env.get_pageserver_version() def start(self, overrides=()) -> "NeonPageserver": """ @@ -1671,10 +1664,19 @@ class NeonPageserver(PgProtocol): def __exit__(self, exc_type, exc, tb): self.stop(immediate=True) + def is_testing_enabled_or_skip(self): + if "testing:true" not in self.version: + pytest.skip("pageserver was built without 'testing' feature") + + def is_profiling_enabled_or_skip(self): + if "profiling:true" not in self.version: + pytest.skip("pageserver was built without 'profiling' feature") + def http_client(self, auth_token: Optional[str] = None) -> NeonPageserverHttpClient: return NeonPageserverHttpClient( port=self.service_port.http, auth_token=auth_token, + is_testing_enabled_or_skip=self.is_testing_enabled_or_skip, ) diff --git a/test_runner/performance/test_perf_pgbench.py b/test_runner/performance/test_perf_pgbench.py index 656826d6a3..0ed3e45971 100644 --- a/test_runner/performance/test_perf_pgbench.py +++ b/test_runner/performance/test_perf_pgbench.py @@ -9,7 +9,6 @@ from typing import Dict, List import pytest from fixtures.benchmark_fixture import MetricReport, PgBenchInitResult, PgBenchRunResult from fixtures.compare_fixtures import NeonCompare, PgCompare -from fixtures.neon_fixtures import profiling_supported from fixtures.utils import get_scale_for_db @@ -187,10 +186,8 @@ def test_pgbench_flamegraph(zenbenchmark, pg_bin, neon_env_builder, scale: int, neon_env_builder.pageserver_config_override = """ profiling="page_requests" """ - if not profiling_supported(): - pytest.skip("pageserver was built without 'profiling' feature") - env = neon_env_builder.init_start() + env.pageserver.is_profiling_enabled_or_skip() env.neon_cli.create_branch("empty", "main") neon_compare = NeonCompare(zenbenchmark, env, pg_bin, "pgbench") diff --git a/test_runner/regress/test_recovery.py b/test_runner/regress/test_recovery.py index d0ba96e8e0..e70b1351ba 100644 --- a/test_runner/regress/test_recovery.py +++ b/test_runner/regress/test_recovery.py @@ -13,13 +13,8 @@ def test_pageserver_recovery(neon_env_builder: NeonEnvBuilder): neon_env_builder.pageserver_config_override = "tenant_config={checkpoint_distance = 1048576}" env = neon_env_builder.init() + env.pageserver.is_testing_enabled_or_skip() - # Check if failpoints enables. Otherwise the test doesn't make sense - f = env.neon_cli.pageserver_enabled_features() - - assert ( - "testing" in f["features"] - ), "Build pageserver with --features=testing option to run this test" neon_env_builder.start() # Create a branch for us diff --git a/test_runner/regress/test_tenant_relocation.py b/test_runner/regress/test_tenant_relocation.py index a3245d65e4..e14434ffdc 100644 --- a/test_runner/regress/test_tenant_relocation.py +++ b/test_runner/regress/test_tenant_relocation.py @@ -346,7 +346,11 @@ def test_tenant_relocation( log.info("new pageserver ports pg %s http %s", new_pageserver_pg_port, new_pageserver_http_port) pageserver_bin = pathlib.Path(neon_binpath) / "pageserver" - new_pageserver_http = NeonPageserverHttpClient(port=new_pageserver_http_port, auth_token=None) + new_pageserver_http = NeonPageserverHttpClient( + port=new_pageserver_http_port, + auth_token=None, + is_testing_enabled_or_skip=env.pageserver.is_testing_enabled_or_skip, + ) with new_pageserver_helper( new_pageserver_dir,