Skip to content

Commit 4e7cc45

Browse files
aarthy-dkclaude
andcommitted
fix(standalone): resolve embedded host/port at connection-build time
Windows pgserver picks a fresh ephemeral TCP port on every startup, so the demo-DB connection row written during quick-start became stale as soon as run-app started a new pgserver session — "Test Connection" and any target-DB query failed with "connection refused". Store a <embedded> sentinel in project_host instead of the live host/port; resolve_connection_params rewrites it to the live values when standalone mode is active. Single chokepoint covers UI test-connection, profiling, test execution, and quick-start increments. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ab6697e commit 4e7cc45

4 files changed

Lines changed: 26 additions & 10 deletions

File tree

testgen/commands/run_launch_db_config.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from testgen.common.models import with_database_session
1010
from testgen.common.read_file import get_template_files
1111
from testgen.common.read_yaml_metadata_records import import_metadata_records_from_yaml
12-
from testgen.common.standalone_postgres import get_target_host_port, is_standalone_mode
12+
from testgen.common.standalone_postgres import EMBEDDED_HOST_SENTINEL, is_standalone_mode
1313

1414
LOG = logging.getLogger("testgen")
1515

@@ -28,9 +28,10 @@ def _get_params_mapping() -> dict:
2828
project_user = settings.PROJECT_DATABASE_USER
2929
project_password = settings.PROJECT_DATABASE_PASSWORD
3030
if is_standalone_mode():
31-
project_host, server_port = get_target_host_port()
32-
if server_port:
33-
project_port = server_port
31+
# Live host/port are resolved at connection-build time via the sentinel
32+
# so the row survives pgserver picking a fresh ephemeral port on Windows.
33+
project_host = EMBEDDED_HOST_SENTINEL
34+
project_port = ""
3435
project_user = "postgres"
3536
project_password = ""
3637

testgen/commands/run_quick_start.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from testgen.common.models.table_group import TableGroup
2828
from testgen.common.notifications.base import smtp_configured
2929
from testgen.common.read_file import read_template_sql_file
30-
from testgen.common.standalone_postgres import get_target_host_port, is_standalone_mode
30+
from testgen.common.standalone_postgres import EMBEDDED_HOST_SENTINEL, is_standalone_mode
3131

3232
LOG = logging.getLogger("testgen")
3333
random.seed(42)
@@ -148,9 +148,10 @@ def _get_settings_params_mapping() -> dict:
148148
admin_user = settings.DATABASE_ADMIN_USER
149149
admin_password = settings.DATABASE_ADMIN_PASSWORD
150150
if is_standalone_mode():
151-
host, server_port = get_target_host_port()
152-
if server_port:
153-
port = server_port
151+
# Live host/port are resolved at connection-build time via the sentinel
152+
# so the row survives pgserver picking a fresh ephemeral port on Windows.
153+
host = EMBEDDED_HOST_SENTINEL
154+
port = ""
154155
admin_user = "postgres"
155156
admin_password = ""
156157

testgen/common/database/flavor/flavor_service.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,20 @@ def _decrypt_if_needed(value: Any) -> str | None:
6161

6262
def resolve_connection_params(connection_params: ConnectionParams) -> ResolvedConnectionParams:
6363
sql_flavor = connection_params.get("sql_flavor") or ""
64+
host = connection_params.get("project_host") or ""
65+
port = connection_params.get("project_port") or ""
66+
# Lazy import to keep the flavor layer free of standalone concerns at module load.
67+
from testgen.common.standalone_postgres import EMBEDDED_HOST_SENTINEL, get_target_host_port, is_standalone_mode
68+
if host == EMBEDDED_HOST_SENTINEL and is_standalone_mode():
69+
host, live_port = get_target_host_port()
70+
port = live_port or ""
6471
return ResolvedConnectionParams(
6572
url=connection_params.get("url") or "",
6673
connect_by_url=connection_params.get("connect_by_url", False),
6774
username=connection_params.get("project_user") or "",
6875
password=_decrypt_if_needed(connection_params.get("project_pw_encrypted")),
69-
host=connection_params.get("project_host") or "",
70-
port=connection_params.get("project_port") or "",
76+
host=host,
77+
port=port,
7178
dbname=connection_params.get("project_db") or "",
7279
dbschema=connection_params.get("table_group_schema"),
7380
sql_flavor=sql_flavor,

testgen/common/standalone_postgres.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@
2323
HOME_DIR_ENV_VAR = "TG_TESTGEN_HOME"
2424
STANDALONE_URI_ENV_VAR = "_TG_STANDALONE_URI"
2525

26+
# Stored as ``project_host`` in the demo-DB connection row so that the actual
27+
# host/port — which can change across sessions on Windows (pgserver picks a
28+
# fresh ephemeral TCP port each startup) — are resolved at connection-build
29+
# time by ``resolve_connection_params``. Angle brackets are illegal in real
30+
# hostnames, so this can't collide with a user-defined connection.
31+
EMBEDDED_HOST_SENTINEL = "<embedded>"
32+
2633

2734
def get_home_dir() -> Path:
2835
env_dir = os.getenv(HOME_DIR_ENV_VAR)

0 commit comments

Comments
 (0)