Skip to content

Commit 605ad35

Browse files
fixes
1 parent d3c1866 commit 605ad35

File tree

4 files changed

+62
-39
lines changed

4 files changed

+62
-39
lines changed

examples/usage_alerts.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
import os
77
import sys
88
import json
9+
from ns1 import NS1
10+
from ns1.config import Config
911

1012
# Path hackery to ensure we import the local ns1 module
1113
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
12-
'..')))
13-
14-
from ns1 import NS1
14+
'..')))
1515

1616
# Create NS1 client
1717
config = {
@@ -26,11 +26,12 @@
2626
}
2727

2828
# Create a config from dictionary and create the client
29-
from ns1.config import Config
3029
c = Config()
3130
c.loadFromDict(config)
3231
client = NS1(config=c)
3332

33+
34+
3435
# Usage Alerts API Examples
3536
def usage_alerts_example():
3637
print("\n=== Usage Alerts Examples ===\n")
@@ -90,6 +91,8 @@ def usage_alerts_example():
9091
except Exception as e:
9192
print(f"Error deleting alert: {e}")
9293

94+
95+
9396
# Test validation failures
9497
def test_validation():
9598
print("\n=== Validation Tests ===\n")
@@ -127,6 +130,8 @@ def test_validation():
127130
except ValueError as e:
128131
print(f"Validation error (expected): {e}")
129132

133+
134+
130135
if __name__ == '__main__':
131136
print("Usage Alerts API Examples")
132137
print("-" * 30)

ns1/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ def alerting(self):
249249
:return: Alerting namespace
250250
"""
251251
from ns1.alerting import UsageAlertsAPI
252-
252+
253253
# Create or reuse the alerting namespace
254254
ns = getattr(self, "_alerting_ns", None)
255255
if ns is None:

ns1/alerting/usage_alerts.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"rum_decision_usage", "filter_chain_usage", "monitor_usage",
66
}
77

8+
89
def _validate(name: str, subtype: str, alert_at_percent: int) -> None:
910
if not name:
1011
raise ValueError("name required")
@@ -13,6 +14,7 @@ def _validate(name: str, subtype: str, alert_at_percent: int) -> None:
1314
if not isinstance(alert_at_percent, int) or not (1 <= alert_at_percent <= 100):
1415
raise ValueError("data.alert_at_percent must be int in 1..100")
1516

17+
1618
class UsageAlertsAPI:
1719
"""
1820
Account-scoped usage alerts.

tests/unit/test_usage_alerts.py

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
except ImportError:
1111
import mock
1212

13-
import json
1413

1514

1615
@pytest.fixture
@@ -32,13 +31,14 @@ def usage_alerts_client(config):
3231
return client
3332

3433

34+
3535
def test_create_usage_alert(usage_alerts_client):
3636
"""Test creating a usage alert"""
3737
client = usage_alerts_client
38-
38+
3939
# Create a mock for the _post method in alerting().usage
40-
client.alerting()._c._post = mock.MagicMock()
41-
client.alerting()._c._post.return_value = {
40+
client._post = mock.MagicMock()
41+
client._post.return_value = {
4242
"id": "a1b2c3",
4343
"name": "Test Alert",
4444
"type": "account",
@@ -50,12 +50,14 @@ def test_create_usage_alert(usage_alerts_client):
5050
"updated_at": 1597937213
5151
}
5252

53-
alert = client.alerting().usage.create(
54-
name="Test Alert",
55-
subtype="query_usage",
56-
alert_at_percent=85,
57-
notifier_list_ids=["n1"]
58-
)
53+
# Patch the client reference
54+
with mock.patch.object(client.alerting().usage, "_c", client):
55+
alert = client.alerting().usage.create(
56+
name="Test Alert",
57+
subtype="query_usage",
58+
alert_at_percent=85,
59+
notifier_list_ids=["n1"]
60+
)
5961

6062
# Verify _post was called with correct arguments
6163
expected_body = {
@@ -66,7 +68,7 @@ def test_create_usage_alert(usage_alerts_client):
6668
"notifier_list_ids": ["n1"],
6769
"zone_names": []
6870
}
69-
client.alerting()._c._post.assert_called_once_with("/alerting/v1/alerts", json=expected_body)
71+
client._post.assert_called_once_with("/alerting/v1/alerts", json=expected_body)
7072

7173
# Verify result
7274
assert alert["id"] == "a1b2c3"
@@ -76,14 +78,15 @@ def test_create_usage_alert(usage_alerts_client):
7678
assert alert["data"]["alert_at_percent"] == 85
7779

7880

81+
7982
def test_get_usage_alert(usage_alerts_client):
8083
"""Test retrieving a usage alert"""
8184
client = usage_alerts_client
8285
alert_id = "a1b2c3"
8386

8487
# Create a mock for the _get method
85-
client.alerting()._c._get = mock.MagicMock()
86-
client.alerting()._c._get.return_value = {
88+
client._get = mock.MagicMock()
89+
client._get.return_value = {
8790
"id": alert_id,
8891
"name": "Test Alert",
8992
"type": "account",
@@ -93,25 +96,28 @@ def test_get_usage_alert(usage_alerts_client):
9396
"zone_names": []
9497
}
9598

96-
alert = client.alerting().usage.get(alert_id)
99+
# Patch the client reference
100+
with mock.patch.object(client.alerting().usage, "_c", client):
101+
alert = client.alerting().usage.get(alert_id)
97102

98103
# Verify _get was called with correct URL
99-
client.alerting()._c._get.assert_called_once_with(f"/alerting/v1/alerts/{alert_id}")
104+
client._get.assert_called_once_with(f"/alerting/v1/alerts/{alert_id}")
100105

101106
# Verify result
102107
assert alert["id"] == alert_id
103108
assert alert["name"] == "Test Alert"
104109
assert alert["data"]["alert_at_percent"] == 85
105110

106111

112+
107113
def test_patch_usage_alert(usage_alerts_client):
108114
"""Test patching a usage alert - verify type/subtype are not sent"""
109115
client = usage_alerts_client
110116
alert_id = "a1b2c3"
111117

112118
# Create a mock for the _patch method
113-
client.alerting()._c._patch = mock.MagicMock()
114-
client.alerting()._c._patch.return_value = {
119+
client._patch = mock.MagicMock()
120+
client._patch.return_value = {
115121
"id": alert_id,
116122
"name": "Updated Alert",
117123
"type": "account",
@@ -121,21 +127,23 @@ def test_patch_usage_alert(usage_alerts_client):
121127
"zone_names": []
122128
}
123129

124-
alert = client.alerting().usage.patch(
125-
alert_id,
126-
name="Updated Alert",
127-
alert_at_percent=90
128-
)
130+
# Patch the client reference
131+
with mock.patch.object(client.alerting().usage, "_c", client):
132+
alert = client.alerting().usage.patch(
133+
alert_id,
134+
name="Updated Alert",
135+
alert_at_percent=90
136+
)
129137

130138
# Verify _patch was called with correct arguments
131139
expected_body = {
132140
"name": "Updated Alert",
133141
"data": {"alert_at_percent": 90}
134142
}
135-
client.alerting()._c._patch.assert_called_once_with(f"/alerting/v1/alerts/{alert_id}", json=expected_body)
143+
client._patch.assert_called_once_with(f"/alerting/v1/alerts/{alert_id}", json=expected_body)
136144

137145
# Verify type/subtype are not in the arguments
138-
call_args = client.alerting()._c._patch.call_args[1]["json"]
146+
call_args = client._patch.call_args[1]["json"]
139147
assert "type" not in call_args
140148
assert "subtype" not in call_args
141149

@@ -145,27 +153,31 @@ def test_patch_usage_alert(usage_alerts_client):
145153
assert alert["data"]["alert_at_percent"] == 90
146154

147155

156+
148157
def test_delete_usage_alert(usage_alerts_client):
149158
"""Test deleting a usage alert"""
150159
client = usage_alerts_client
151160
alert_id = "a1b2c3"
152161

153162
# Create a mock for the _delete method
154-
client.alerting()._c._delete = mock.MagicMock()
163+
client._delete = mock.MagicMock()
155164

156-
client.alerting().usage.delete(alert_id)
165+
# Patch the client reference
166+
with mock.patch.object(client.alerting().usage, "_c", client):
167+
client.alerting().usage.delete(alert_id)
157168

158169
# Verify _delete was called with correct URL
159-
client.alerting()._c._delete.assert_called_once_with(f"/alerting/v1/alerts/{alert_id}")
170+
client._delete.assert_called_once_with(f"/alerting/v1/alerts/{alert_id}")
171+
160172

161173

162174
def test_list_usage_alerts(usage_alerts_client):
163175
"""Test listing usage alerts with pagination params"""
164176
client = usage_alerts_client
165177

166178
# Create a mock for the _get method
167-
client.alerting()._c._get = mock.MagicMock()
168-
client.alerting()._c._get.return_value = {
179+
client._get = mock.MagicMock()
180+
client._get.return_value = {
169181
"limit": 1,
170182
"next": "next_token",
171183
"total_results": 2,
@@ -180,17 +192,19 @@ def test_list_usage_alerts(usage_alerts_client):
180192
]
181193
}
182194

183-
response = client.alerting().usage.list(
184-
limit=1,
185-
order_descending=True
186-
)
195+
# Patch the client reference
196+
with mock.patch.object(client.alerting().usage, "_c", client):
197+
response = client.alerting().usage.list(
198+
limit=1,
199+
order_descending=True
200+
)
187201

188202
# Verify _get was called with correct URL and params
189203
expected_params = {
190204
"limit": 1,
191205
"order_descending": "true"
192206
}
193-
client.alerting()._c._get.assert_called_once_with("/alerting/v1/alerts", params=expected_params)
207+
client._get.assert_called_once_with("/alerting/v1/alerts", params=expected_params)
194208

195209
# Verify result
196210
assert "results" in response
@@ -201,6 +215,7 @@ def test_list_usage_alerts(usage_alerts_client):
201215
assert response["results"][0]["id"] == "a1"
202216

203217

218+
204219
def test_validation_threshold_bounds(usage_alerts_client):
205220
"""Test validation of alert_at_percent bounds"""
206221
client = usage_alerts_client
@@ -232,6 +247,7 @@ def test_validation_threshold_bounds(usage_alerts_client):
232247
assert "alert_at_percent must be int in 1..100" in str(excinfo.value)
233248

234249

250+
235251
def test_validation_subtype():
236252
"""Test validation of subtype values"""
237253
from ns1.alerting import USAGE_SUBTYPES

0 commit comments

Comments
 (0)