Skip to content

Commit 875d96f

Browse files
committed
Delete testing RDS instance for cost efficiency
1 parent fab9e0b commit 875d96f

File tree

7 files changed

+94
-57
lines changed

7 files changed

+94
-57
lines changed

tests/conftest.py

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
REGION_NAME: BucketLocationConstraintType = "eu-central-1"
1818

1919

20-
@pytest.fixture(scope="module")
20+
@pytest.fixture(scope="session")
2121
def monkeypatch_module() -> Generator[pytest.MonkeyPatch, Any, None]:
2222
with pytest.MonkeyPatch.context() as mp:
2323
yield mp
2424

2525

26-
@pytest.fixture(autouse=True, scope="module")
26+
@pytest.fixture(autouse=True, scope="session")
2727
def patch_update_job(monkeypatch_module: pytest.MonkeyPatch) -> MagicMock:
2828
mock_update_job = MagicMock()
2929
monkeypatch_module.setattr(job_tracking, "update_job", mock_update_job)
@@ -33,14 +33,16 @@ def patch_update_job(monkeypatch_module: pytest.MonkeyPatch) -> MagicMock:
3333
class RDSTestingInstance:
3434
def __init__(self, db_name: str):
3535
self.db_name = db_name
36+
37+
def create(self) -> None:
3638
self.rds_client = boto3.client("rds", "eu-central-1")
3739
self.ec2_client = boto3.client("ec2", "eu-central-1")
3840
self.add_ingress_rule()
3941
self.db_url = self.create_db_url()
42+
self.engine = self.get_engine()
4043
self.delete_db_tables()
4144

42-
@property
43-
def engine(self) -> Engine:
45+
def get_engine(self) -> Engine:
4446
for _ in range(5):
4547
try:
4648
engine = create_engine(self.db_url)
@@ -112,12 +114,14 @@ def create_db_url(self) -> str:
112114
DBName=self.db_name,
113115
DBInstanceIdentifier=self.db_name,
114116
AllocatedStorage=20,
115-
DBInstanceClass="db.t3.micro",
117+
DBInstanceClass="db.t4g.micro",
116118
Engine="postgres",
117119
MasterUsername=user,
118120
MasterUserPassword=password,
119121
DeletionProtection=False,
120122
BackupRetentionPeriod=0,
123+
MultiAZ=False,
124+
EnablePerformanceInsights=False,
121125
)
122126
break
123127
except self.rds_client.exceptions.DBInstanceAlreadyExistsFault:
@@ -138,19 +142,34 @@ def cleanup(self) -> None:
138142
self.delete_db_tables()
139143
self.ec2_client.revoke_security_group_ingress(**self.vpc_sg_rule_params)
140144

145+
def delete(self) -> None:
146+
self.rds_client.delete_db_instance(
147+
DBInstanceIdentifier=self.db_name,
148+
SkipFinalSnapshot=True,
149+
DeleteAutomatedBackups=True,
150+
)
151+
141152

142153
class S3TestingBucket:
143154
def __init__(self, bucket_name_suffix: str):
144155
# S3 bucket names must be globally unique - avoid collisions by adding suffix
145156
self.bucket_name = f"{TEST_BUCKET_PREFIX}-{bucket_name_suffix}"
146157
self.region_name: BucketLocationConstraintType = REGION_NAME
158+
159+
def create(self) -> None:
147160
self.s3_client = boto3.client(
148161
"s3",
149162
region_name=self.region_name,
150163
# required for pre-signing URLs to work
151164
endpoint_url=f"https://s3.{self.region_name}.amazonaws.com",
152165
)
153-
self.initialize_bucket()
166+
exists = self.cleanup()
167+
if not exists:
168+
self.s3_client.create_bucket(
169+
Bucket=self.bucket_name,
170+
CreateBucketConfiguration={"LocationConstraint": self.region_name},
171+
)
172+
self.s3_client.get_waiter("bucket_exists").wait(Bucket=self.bucket_name)
154173

155174
def cleanup(self) -> bool:
156175
"""Returns True if bucket exists and all objects are deleted."""
@@ -169,19 +188,21 @@ def cleanup(self) -> bool:
169188
s3_bucket.objects.all().delete()
170189
return True
171190

172-
def initialize_bucket(self) -> None:
191+
def delete(self) -> None:
173192
exists = self.cleanup()
174-
if not exists:
175-
self.s3_client.create_bucket(
176-
Bucket=self.bucket_name,
177-
CreateBucketConfiguration={"LocationConstraint": self.region_name},
178-
)
179-
self.s3_client.get_waiter("bucket_exists").wait(Bucket=self.bucket_name)
193+
if exists:
194+
self.s3_client.delete_bucket(Bucket=self.bucket_name)
195+
196+
197+
@pytest.fixture(scope="session")
198+
def rds_testing_instance() -> RDSTestingInstance:
199+
return RDSTestingInstance("decodecloudintegrationtestsworkerapi")
180200

181201

182202
@pytest.fixture(scope="session")
183-
def bucket_suffix() -> str:
184-
return datetime.datetime.now(datetime.UTC).strftime("%Y%m%d%H%M%S")
203+
def s3_testing_bucket() -> S3TestingBucket:
204+
bucket_suffix = datetime.datetime.now(datetime.UTC).strftime("%Y%m%d%H%M%S")
205+
return S3TestingBucket(bucket_suffix)
185206

186207

187208
@pytest.mark.aws

tests/integration/conftest.py

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import shutil
2-
from typing import Any, Generator
2+
from typing import Any, Generator, cast
33

44
import pytest
55

@@ -18,33 +18,46 @@
1818
from workerfacing_api.main import workerfacing_app
1919

2020

21-
@pytest.fixture(scope="module")
21+
@pytest.fixture(scope="session")
2222
def test_username() -> str:
2323
return "test_user"
2424

2525

26-
@pytest.fixture(scope="module")
26+
@pytest.fixture(scope="session")
2727
def base_dir() -> str:
2828
return "int_test_dir"
2929

3030

31-
@pytest.fixture(scope="module")
31+
@pytest.fixture(scope="session")
3232
def internal_api_key_secret() -> str:
3333
return "test_internal_api_key"
3434

3535

3636
@pytest.fixture(
37-
scope="module",
37+
scope="session",
3838
params=["local", pytest.param("aws", marks=pytest.mark.aws)],
3939
)
40-
def env(request: pytest.FixtureRequest) -> str:
41-
assert isinstance(request.param, str)
42-
return request.param
40+
def env(
41+
request: pytest.FixtureRequest,
42+
rds_testing_instance: RDSTestingInstance,
43+
s3_testing_bucket: S3TestingBucket,
44+
) -> Generator[str, Any, None]:
45+
env = cast(str, request.param)
46+
if env == "aws":
47+
rds_testing_instance.create()
48+
s3_testing_bucket.create()
49+
yield env
50+
if env == "aws":
51+
rds_testing_instance.delete()
52+
s3_testing_bucket.delete()
4353

4454

45-
@pytest.fixture(scope="module")
55+
@pytest.fixture(scope="session")
4656
def base_filesystem(
47-
env: str, base_dir: str, monkeypatch_module: pytest.MonkeyPatch, bucket_suffix: str
57+
env: str,
58+
base_dir: str,
59+
monkeypatch_module: pytest.MonkeyPatch,
60+
s3_testing_bucket: S3TestingBucket,
4861
) -> Generator[FileSystem, Any, None]:
4962
monkeypatch_module.setattr(
5063
settings,
@@ -63,39 +76,39 @@ def base_filesystem(
6376
shutil.rmtree(base_dir, ignore_errors=True)
6477

6578
elif env == "aws":
66-
testing_bucket = S3TestingBucket(bucket_suffix)
6779
# Update settings to use the actual unique bucket name created by S3TestingBucket
6880
monkeypatch_module.setattr(
6981
settings,
7082
"s3_bucket",
71-
testing_bucket.bucket_name,
83+
s3_testing_bucket.bucket_name,
7284
)
73-
yield S3Filesystem(testing_bucket.s3_client, testing_bucket.bucket_name)
74-
testing_bucket.cleanup()
85+
yield S3Filesystem(s3_testing_bucket.s3_client, s3_testing_bucket.bucket_name)
86+
s3_testing_bucket.cleanup()
7587

7688
else:
7789
raise NotImplementedError
7890

7991

80-
@pytest.fixture(scope="module")
92+
@pytest.fixture(scope="session")
8193
def queue(
82-
env: str, tmpdir_factory: pytest.TempdirFactory
94+
env: str,
95+
rds_testing_instance: RDSTestingInstance,
96+
tmpdir_factory: pytest.TempdirFactory,
8397
) -> Generator[RDSJobQueue, Any, None]:
8498
if env == "local":
8599
queue = RDSJobQueue(
86100
f"sqlite:///{tmpdir_factory.mktemp('integration')}/local.db"
87101
)
88102
else:
89-
db = RDSTestingInstance("decodecloudintegrationtests")
90-
queue = RDSJobQueue(db.db_url)
103+
queue = RDSJobQueue(rds_testing_instance.db_url)
91104
queue.create(err_on_exists=True)
92105
yield queue
93106
queue.delete()
94107
if env == "aws":
95-
db.cleanup()
108+
rds_testing_instance.cleanup()
96109

97110

98-
@pytest.fixture(scope="module", autouse=True)
111+
@pytest.fixture(scope="session", autouse=True)
99112
def override_filesystem_dep(
100113
base_filesystem: FileSystem, monkeypatch_module: pytest.MonkeyPatch
101114
) -> None:
@@ -106,7 +119,7 @@ def override_filesystem_dep(
106119
)
107120

108121

109-
@pytest.fixture(scope="module", autouse=True)
122+
@pytest.fixture(scope="session", autouse=True)
110123
def override_queue_dep(
111124
queue: RDSJobQueue, monkeypatch_module: pytest.MonkeyPatch
112125
) -> None:
@@ -117,7 +130,7 @@ def override_queue_dep(
117130
)
118131

119132

120-
@pytest.fixture(scope="module", autouse=True)
133+
@pytest.fixture(scope="session", autouse=True)
121134
def override_auth(monkeypatch_module: pytest.MonkeyPatch, test_username: str) -> None:
122135
monkeypatch_module.setitem(
123136
workerfacing_app.dependency_overrides, # type: ignore
@@ -132,7 +145,7 @@ def override_auth(monkeypatch_module: pytest.MonkeyPatch, test_username: str) ->
132145
)
133146

134147

135-
@pytest.fixture(scope="module", autouse=True)
148+
@pytest.fixture(scope="session", autouse=True)
136149
def override_internal_api_key_secret(
137150
monkeypatch_module: pytest.MonkeyPatch, internal_api_key_secret: str
138151
) -> str:

tests/integration/endpoints/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ class _TestEndpoint(abc.ABC):
2020
endpoint = ""
2121

2222
@abc.abstractmethod
23-
@pytest.fixture(scope="module")
23+
@pytest.fixture(scope="session")
2424
def passing_params(self, *args: Any, **kwargs: Any) -> list[EndpointParams]:
2525
raise NotImplementedError
2626

27-
@pytest.fixture(scope="module")
27+
@pytest.fixture(scope="session")
2828
def client(self) -> TestClient:
2929
return TestClient(workerfacing_app)
3030

tests/integration/endpoints/test_files.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,25 @@
1010
from workerfacing_api.core.filesystem import FileSystem, S3Filesystem
1111

1212

13-
@pytest.fixture(scope="module")
13+
@pytest.fixture(scope="session")
1414
def data_file1_name(base_dir: str) -> str:
1515
return f"{base_dir}/data/test/data_file1.txt"
1616

1717

18-
@pytest.fixture(scope="module")
18+
@pytest.fixture(scope="session")
1919
def data_file1_path(env: str, data_file1_name: str, base_filesystem: FileSystem) -> str:
2020
if env == "aws":
2121
base_filesystem = cast(S3Filesystem, base_filesystem)
2222
return f"s3://{base_filesystem.bucket}/{data_file1_name}"
2323
return data_file1_name
2424

2525

26-
@pytest.fixture(scope="module")
26+
@pytest.fixture(scope="session")
2727
def data_file1_contents() -> str:
2828
return "data_file1"
2929

3030

31-
@pytest.fixture(scope="module", autouse=True)
31+
@pytest.fixture(scope="session", autouse=True)
3232
def data_file1(
3333
env: str,
3434
base_filesystem: FileSystem,
@@ -51,7 +51,7 @@ def data_file1(
5151
class TestFiles(_TestEndpoint):
5252
endpoint = "/files"
5353

54-
@pytest.fixture(scope="module")
54+
@pytest.fixture(scope="session")
5555
def passing_params(self, data_file1_path: str) -> list[EndpointParams]:
5656
return [
5757
EndpointParams("get", f"{data_file1_path}/url"),

tests/integration/endpoints/test_jobs.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,17 @@
2727
from workerfacing_api.schemas.rds_models import JobStates
2828

2929

30-
@pytest.fixture(scope="module")
30+
@pytest.fixture(scope="session")
3131
def app() -> AppSpecs:
3232
return AppSpecs(cmd=["cmd"], env={"env": "var"})
3333

3434

35-
@pytest.fixture(scope="module")
35+
@pytest.fixture(scope="session")
3636
def handler() -> HandlerSpecs:
3737
return HandlerSpecs(image_url="u", files_up={"output": "out"})
3838

3939

40-
@pytest.fixture(scope="module")
40+
@pytest.fixture(scope="session")
4141
def paths_upload(
4242
env: str, test_username: str, base_filesystem: FileSystem
4343
) -> PathsUploadSpecs:
@@ -55,7 +55,7 @@ def paths_upload(
5555
class TestJobs(_TestEndpoint):
5656
endpoint = "/jobs"
5757

58-
@pytest.fixture(scope="module")
58+
@pytest.fixture(scope="session")
5959
def passing_params(self) -> list[EndpointParams]:
6060
return [EndpointParams("get", params={"memory": 1})]
6161

tests/unit/core/test_filesystem.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,15 @@ def mock_aws_(self, request: pytest.FixtureRequest) -> bool:
232232

233233
@pytest.fixture(scope="class")
234234
def base_filesystem(
235-
self, mock_aws_: bool, bucket_suffix: str
235+
self, mock_aws_: bool, s3_testing_bucket: S3TestingBucket
236236
) -> Generator[S3Filesystem, Any, None]:
237237
context_manager = mock_aws if mock_aws_ else nullcontext
238238
with context_manager():
239-
testing_bucket = S3TestingBucket(bucket_suffix)
240-
yield S3Filesystem(testing_bucket.s3_client, testing_bucket.bucket_name)
241-
testing_bucket.cleanup()
239+
s3_testing_bucket.create()
240+
yield S3Filesystem(
241+
s3_testing_bucket.s3_client, s3_testing_bucket.bucket_name
242+
)
243+
s3_testing_bucket.delete()
242244

243245
@pytest.fixture(scope="class", autouse=True)
244246
def data_file1(

tests/unit/core/test_queue.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,8 @@ def base_queue(
301301
@pytest.mark.aws
302302
class TestRDSAWSQueue(_TestRDSQueue):
303303
@pytest.fixture(scope="class")
304-
def base_queue(self) -> Generator[RDSJobQueue, Any, None]:
305-
db = RDSTestingInstance("decodecloudqueuetests")
306-
yield RDSJobQueue(db.db_url)
307-
db.cleanup()
304+
def base_queue(
305+
self, rds_testing_instance: RDSTestingInstance
306+
) -> Generator[RDSJobQueue, Any, None]:
307+
yield RDSJobQueue(rds_testing_instance.db_url)
308+
rds_testing_instance.cleanup()

0 commit comments

Comments
 (0)