Skip to content

Commit ff0c7fd

Browse files
committed
restructure as tests/branches/test_{basic,clone_restore}.py.
1 parent bc11d21 commit ff0c7fd

5 files changed

Lines changed: 173 additions & 187 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,7 @@ testpaths = [
8787
"tests/test_organizations.py",
8888
"tests/test_projects.py",
8989
"tests/test_resources.py",
90-
"tests/test_branches.py",
91-
"tests/test_backup_and_clone.py",
90+
"tests/branches",
9291
]
9392

9493
[tool.ruff]
Lines changed: 32 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,21 @@
11
import time
22

3-
import httpx
43
import psycopg
54
import pytest
6-
from conftest import BRANCH_TIMEOUT_SEC, _id, wait_for_status
5+
from conftest import BRANCH_TIMEOUT_SEC, wait_for_status
76

87
pytestmark = pytest.mark.branch
98

9+
_BRANCH_PASSWORD = "SecurePass1!"
1010
_BRANCH_NAME = "test-branch"
1111
_BRANCH_RENAMED = "test-branch-renamed"
12-
_BRANCH_CREATE_PAYLOAD = {
13-
"name": _BRANCH_NAME,
14-
"deployment": {
15-
"database_password": "SecurePass1!",
16-
"database_size": 1000000000,
17-
"storage_size": 1000000000,
18-
"milli_vcpu": 500,
19-
"memory_bytes": 1073741824,
20-
"iops": 1000,
21-
"database_image_tag": "18.1-velaos",
22-
"enable_file_storage": True,
23-
},
24-
}
25-
26-
_state: dict = {}
2712

2813
_DB_CONNECT_TIMEOUT = 10
2914
_DB_CONNECT_MAX_WAIT = 120
3015
_DB_CONNECT_RETRY_DELAY = 15
3116

17+
_state: dict = {}
18+
3219

3320
def _check_postgres_connection(db_info: dict, password: str) -> None:
3421
"""Verify a Postgres connection can be established with the given credentials.
@@ -58,6 +45,11 @@ def _check_postgres_connection(db_info: dict, password: str) -> None:
5845
raise AssertionError(f"Could not connect to postgres at {host}:{port}: {last_exc}") from last_exc
5946

6047

48+
# ---------------------------------------------------------------------------
49+
# Fixtures
50+
# ---------------------------------------------------------------------------
51+
52+
6153
@pytest.fixture(scope="module")
6254
def org(make_org):
6355
return make_org("test-org-branches")
@@ -69,36 +61,31 @@ def project(make_project, org):
6961

7062

7163
@pytest.fixture(scope="module")
72-
def branch_id(client, org, project):
73-
r = client.post(
74-
f"organizations/{org}/projects/{project}/branches/",
75-
json=_BRANCH_CREATE_PAYLOAD,
76-
timeout=60,
64+
def branch_id(client, make_branch, org, project):
65+
bid = make_branch(
66+
org,
67+
project,
68+
_BRANCH_NAME,
69+
deployment={
70+
"database_password": _BRANCH_PASSWORD,
71+
"database_size": 1_000_000_000,
72+
"storage_size": 1_000_000_000,
73+
"milli_vcpu": 500,
74+
"memory_bytes": 1_073_741_824,
75+
"iops": 1000,
76+
"database_image_tag": "18.1-velaos",
77+
"enable_file_storage": True,
78+
},
7779
)
78-
assert r.status_code == 201
79-
bid = _id(r.headers["Location"])
80-
branch_data = wait_for_status(
81-
client,
82-
f"organizations/{org}/projects/{project}/branches/{bid}/",
83-
"ACTIVE_HEALTHY",
84-
BRANCH_TIMEOUT_SEC,
85-
)
86-
_check_postgres_connection(
87-
branch_data["database"],
88-
_BRANCH_CREATE_PAYLOAD["deployment"]["database_password"],
89-
)
90-
yield bid
80+
r = client.get(f"organizations/{org}/projects/{project}/branches/{bid}/")
81+
r.raise_for_status()
82+
_check_postgres_connection(r.json()["database"], _BRANCH_PASSWORD)
83+
return bid
9184

92-
r = client.delete(f"organizations/{org}/projects/{project}/branches/{bid}/")
93-
assert r.status_code == 204
94-
with pytest.raises(httpx.HTTPStatusError) as exc:
95-
wait_for_status(
96-
client,
97-
f"organizations/{org}/projects/{project}/branches/{bid}/",
98-
"DELETED", # Dummy status for now, after soft-delete is implemented this will become the actual check
99-
BRANCH_TIMEOUT_SEC,
100-
)
101-
assert exc.value.response.status_code == 404
85+
86+
# ---------------------------------------------------------------------------
87+
# Tests
88+
# ---------------------------------------------------------------------------
10289

10390

10491
def test_branch_list_empty(client, org, project):
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import pytest
2+
3+
pytestmark = pytest.mark.backup
4+
5+
_BRANCH_PASSWORD = "SecurePass1!"
6+
7+
# ---------------------------------------------------------------------------
8+
# Fixtures
9+
# ---------------------------------------------------------------------------
10+
11+
12+
@pytest.fixture(scope="module")
13+
def org(make_org):
14+
return make_org("test-org-backup", max_backups=10)
15+
16+
17+
@pytest.fixture(scope="module")
18+
def project(make_project, org):
19+
return make_project(org, "test-project-backup", max_backups=10)
20+
21+
22+
@pytest.fixture(scope="module")
23+
def branch_id(make_branch, org, project):
24+
return make_branch(
25+
org,
26+
project,
27+
"test-branch-backup",
28+
deployment={
29+
"database_password": _BRANCH_PASSWORD,
30+
"database_size": 5_000_000_000,
31+
"storage_size": 5_000_000_000,
32+
"milli_vcpu": 500,
33+
"memory_bytes": 1_073_741_824,
34+
"iops": 1000,
35+
"database_image_tag": "18.1-velaos",
36+
"enable_file_storage": False,
37+
},
38+
)
39+
40+
41+
@pytest.fixture(scope="module")
42+
def backup_id(client, branch_id):
43+
"""Trigger a manual backup and return the backup_id."""
44+
r = client.post(f"backup/branches/{branch_id}/", timeout=120)
45+
assert r.status_code == 200
46+
data = r.json()
47+
assert data["status"] == "manual backup created"
48+
assert "backup_id" in data
49+
return data["backup_id"]
50+
51+
52+
# ---------------------------------------------------------------------------
53+
# Branch Clone
54+
# ---------------------------------------------------------------------------
55+
56+
57+
def test_branch_clone(client, org, project, branch_id, make_branch):
58+
"""Clone a branch and verify the clone reaches ACTIVE_HEALTHY."""
59+
clone_id = make_branch(
60+
org,
61+
project,
62+
"test-branch-clone",
63+
source={"branch_id": str(branch_id), "data_copy": True},
64+
)
65+
r = client.get(f"organizations/{org}/projects/{project}/branches/{clone_id}/")
66+
assert r.status_code == 200
67+
assert r.json()["status"] == "ACTIVE_HEALTHY"
68+
69+
70+
# ---------------------------------------------------------------------------
71+
# Manual Backup
72+
# ---------------------------------------------------------------------------
73+
74+
75+
def test_manual_backup(backup_id):
76+
"""Trigger an on-demand backup for the branch and verify a backup_id is returned."""
77+
assert backup_id, "backup_id fixture must return a valid id"
78+
79+
80+
# ---------------------------------------------------------------------------
81+
# Restore a new branch from backup
82+
# ---------------------------------------------------------------------------
83+
84+
85+
def test_restore_branch_from_backup(client, org, project, backup_id, make_branch):
86+
"""Create a new branch from the manual backup and verify it reaches ACTIVE_HEALTHY."""
87+
restored_id = make_branch(
88+
org,
89+
project,
90+
"test-branch-restored",
91+
restore={"backup_id": backup_id},
92+
)
93+
r = client.get(f"organizations/{org}/projects/{project}/branches/{restored_id}/")
94+
assert r.status_code == 200
95+
assert r.json()["status"] == "ACTIVE_HEALTHY"

tests/conftest.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,48 @@ def _factory(org_id: ULID, name: str, **overrides: object) -> ULID:
115115
yield _factory
116116
for org_id, uid in created:
117117
client.delete(f"organizations/{org_id}/projects/{uid}/")
118+
119+
120+
@pytest.fixture(scope="session")
121+
def make_branch(client):
122+
"""Factory that creates a branch, waits for ACTIVE_HEALTHY, and deletes on teardown.
123+
124+
Provides sensible deployment defaults. Pass ``deployment={…}`` to override.
125+
For clones pass ``source={…}``; for restores pass ``restore={…}`` – deployment
126+
defaults are omitted automatically in those cases.
127+
"""
128+
default_deployment: dict = {
129+
"database_password": "SecurePass1!",
130+
"database_size": 1_000_000_000,
131+
"storage_size": 1_000_000_000,
132+
"milli_vcpu": 500,
133+
"memory_bytes": 1_073_741_824,
134+
"iops": 1000,
135+
"database_image_tag": "18.1-velaos",
136+
"enable_file_storage": False,
137+
}
138+
created: list[tuple[ULID, ULID, ULID]] = []
139+
140+
def _factory(org_id: ULID, project_id: ULID, name: str, **overrides: object) -> ULID:
141+
payload: dict = {"name": name, **overrides}
142+
if "deployment" not in payload and "source" not in payload and "restore" not in payload:
143+
payload["deployment"] = {**default_deployment}
144+
r = client.post(
145+
f"organizations/{org_id}/projects/{project_id}/branches/",
146+
json=payload,
147+
timeout=60,
148+
)
149+
assert r.status_code == 201
150+
uid = _id(r.headers["Location"])
151+
wait_for_status(
152+
client,
153+
f"organizations/{org_id}/projects/{project_id}/branches/{uid}/",
154+
"ACTIVE_HEALTHY",
155+
BRANCH_TIMEOUT_SEC,
156+
)
157+
created.append((org_id, project_id, uid))
158+
return uid
159+
160+
yield _factory
161+
for org_id, project_id, uid in reversed(created):
162+
client.delete(f"organizations/{org_id}/projects/{project_id}/branches/{uid}/")

0 commit comments

Comments
 (0)