Skip to content

Commit 1f61ee1

Browse files
committed
Add test for creating log group(s)
1 parent ae61fed commit 1f61ee1

1 file changed

Lines changed: 99 additions & 8 deletions

File tree

‎tests/test_startCluster.py‎

Lines changed: 99 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import json
2+
from types import MethodType
23

34
import boto3
45
import pytest
5-
from moto import mock_ecs, mock_sqs, mock_s3, mock_ec2
6+
from moto import mock_ecs, mock_sqs, mock_s3, mock_ec2, mock_logs
67

78
import run
89
import config
@@ -51,26 +52,61 @@ def test_generate_ecs_config(self, s3, run_submitJob, tmp_path):
5152
class EarlyTermination(Exception):
5253
...
5354

54-
def hijack_client(real_client, service_name):
55+
def hijack_client(real_client, service_name, service_fn=None, service_count=1, service_fn_count=1):
5556
"""
56-
Patches boto3.client so that an invocation of a service
57+
If service_fn is None,
58+
Patches boto3.client('<some_service>') so that an invocation of a service
5759
(eg 'ec2' or 'logs') will raise an EarlyTermination exception, allowing
5860
inspection and testing of the stack frame up until that point.
61+
62+
If service_fn is not None,
63+
Patches boto3.client('<some_service>').<service_fn> so that an invocation
64+
of a service function (eg 'put_retention_policy') will raise an EarlyTermination
65+
exception, allowing inspection and testing of the stack frame up until that point.
66+
67+
'service_count' represents the number of times the service can be called
68+
before the EarlyTermination exception is raised.
69+
70+
`service_fn_count` represents the number of times the service function can be called
71+
before the EarlyTermination exception is raised.
5972
"""
73+
if service_fn is None:
74+
real_client._called_n_times = service_count
75+
6076
def f(*args, **kwargs):
61-
if (args[0] == service_name):
62-
raise EarlyTermination("early termination")
63-
64-
return real_client(*args, **kwargs)
77+
real_client_obj = real_client(*args, **kwargs)
78+
79+
if service_fn is None and args[0] == service_name:
80+
real_client._called_n_times -= 1
81+
if real_client._called_n_times == 0:
82+
raise EarlyTermination("early termination")
83+
84+
elif service_fn is not None and args[0] == service_name:
85+
real_client_obj._called_n_times = service_fn_count
86+
87+
real_fn = getattr(real_client_obj, service_fn)
88+
89+
def hijacked_fn(*args, **kwargs):
90+
real_fn(*args, **kwargs)
91+
real_client_obj._called_n_times -= 1
92+
if real_client_obj._called_n_times == 0:
93+
raise EarlyTermination("early termination")
94+
95+
setattr(real_client_obj, service_fn, hijacked_fn)
96+
97+
return real_client_obj
6598

6699
return f
67100

68-
class TestSpotFleetConfig:
69101

102+
class TestSpotFleetConfig:
70103
@mock_ecs
71104
@mock_sqs
72105
@mock_s3
73106
def test_spot_fleet_config(self, run_startCluster, monkeypatch):
107+
"""
108+
startCluster Step 1: set up the configuration files
109+
"""
74110
monkeypatch.setattr(boto3, "client", hijack_client(boto3.client, 'ec2'))
75111
with pytest.raises(EarlyTermination) as e_info:
76112
run_startCluster()
@@ -141,6 +177,9 @@ def test_spot_fleet_config(self, run_startCluster, monkeypatch):
141177
@mock_s3
142178
@mock_ec2
143179
def test_make_spot_fleet_request(self, run_startCluster, monkeypatch):
180+
"""
181+
startCluster Step 2: make the spot fleet request
182+
"""
144183
monkeypatch.setattr(boto3, "client", hijack_client(boto3.client, 'logs'))
145184
with pytest.raises(EarlyTermination) as e_info:
146185
run_startCluster()
@@ -168,6 +207,9 @@ class TestCreateMonitor:
168207
@mock_s3
169208
@mock_ec2
170209
def test_create_monitor(self, run_startCluster, monkeypatch):
210+
"""
211+
startCluster Step 3: Make the monitor
212+
"""
171213
monkeypatch.setattr(boto3, "client", hijack_client(boto3.client, 'logs'))
172214
with pytest.raises(EarlyTermination) as e_info:
173215
run_startCluster()
@@ -189,6 +231,55 @@ def test_create_monitor(self, run_startCluster, monkeypatch):
189231
assert monitor_file_res["MONITOR_LOG_GROUP_NAME"] == config.LOG_GROUP_NAME
190232

191233

234+
class TestCreateLogGroup:
235+
@mock_ecs
236+
@mock_sqs
237+
@mock_s3
238+
@mock_ec2
239+
@mock_logs
240+
def test_create_log_group(self, run_startCluster, monkeypatch):
241+
"""
242+
startCluster Step 4: Create the log group
243+
"""
244+
monkeypatch.setattr(boto3, "client", hijack_client(
245+
boto3.client,
246+
'logs',
247+
service_fn='put_retention_policy',
248+
service_fn_count=2
249+
))
250+
251+
with pytest.raises(EarlyTermination) as e_info:
252+
run_startCluster()
253+
254+
log_group_info_res = None
255+
for tb in e_info.traceback:
256+
if (tb.name == "startCluster"):
257+
log_group_info_res = tb.frame.f_locals["loggroupinfo"]
258+
259+
assert log_group_info_res is not None
260+
assert log_group_info_res["ResponseMetadata"]["HTTPStatusCode"] == 200
261+
262+
logs = boto3.client("logs")
263+
log_group_info_res = logs.describe_log_groups(logGroupNamePrefix=config.LOG_GROUP_NAME)
264+
265+
assert "logGroups" in log_group_info_res
266+
log_groups = log_group_info_res["logGroups"]
267+
268+
name_log_groups = list(filter(
269+
lambda lg: lg["logGroupName"] == config.LOG_GROUP_NAME, log_groups
270+
))
271+
272+
per_instance_log_groups = list(filter(
273+
lambda lg: lg["logGroupName"] == config.LOG_GROUP_NAME + "_perInstance", log_groups
274+
))
275+
276+
assert len(name_log_groups) == 1
277+
assert len(per_instance_log_groups) == 1
278+
279+
assert name_log_groups[0]["arn"] == f"arn:aws:logs:{config.AWS_REGION}:123456789012:log-group:{config.LOG_GROUP_NAME}"
280+
assert per_instance_log_groups[0]["arn"] == f"arn:aws:logs:{config.AWS_REGION}:123456789012:log-group:{config.LOG_GROUP_NAME}_perInstance"
281+
282+
192283
class TestStartCluster:
193284
@mock_ecs
194285
@mock_sqs

0 commit comments

Comments
 (0)