Skip to content

Commit 7b4ba75

Browse files
feat: Add unit tests for /create-newsletter endpoint
1 parent 1b7e4f5 commit 7b4ba75

File tree

1 file changed

+118
-1
lines changed

1 file changed

+118
-1
lines changed

tests/test_api.py

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
from datetime import datetime, timezone
44
from pathlib import Path
5-
from unittest.mock import AsyncMock, patch
5+
from unittest.mock import AsyncMock, MagicMock,patch
66

77
import jwt
88
import pytest # For fixtures
@@ -15,6 +15,7 @@
1515
import mxgo.validators
1616
from mxgo._logging import get_logger
1717
from mxgo.api import app
18+
from mxgo.config import NEWSLETTER_LIMITS_BY_PLAN
1819
from mxgo.schemas import EmailSuggestionResponse, SuggestionDetail, UserPlan
1920
from tests.generate_test_jwt import generate_test_jwt
2021

@@ -1207,3 +1208,119 @@ def test_user_info_api_different_user_emails(
12071208
# Verify the correct email was used for lookups
12081209
mock_get_user_plan.assert_called_once_with("[email protected]")
12091210
mock_get_customer_id.assert_called_once_with("[email protected]")
1211+
1212+
1213+
@patch("mxgo.auth.JWT_SECRET", "test_secret_key_for_development_only")
1214+
class TestCreateNewsletter:
1215+
@pytest.fixture
1216+
def mock_dependencies(self):
1217+
"""Mocks all external dependencies for the newsletter endpoint."""
1218+
with patch("mxgo.api.user.get_user_plan", new_callable=AsyncMock) as mock_get_plan, \
1219+
patch("mxgo.api.crud.count_active_tasks_for_user") as mock_count_tasks, \
1220+
patch("mxgo.api.whitelist.is_email_whitelisted", new_callable=AsyncMock) as mock_is_whitelisted, \
1221+
patch("mxgo.api.Scheduler.add_job") as mock_add_job, \
1222+
patch("mxgo.api.process_email_task.send") as mock_send_task:
1223+
1224+
# Default happy path mocks
1225+
mock_get_plan.return_value = UserPlan.BETA
1226+
mock_count_tasks.return_value = 0
1227+
mock_is_whitelisted.return_value = (True, True) # Assume user is whitelisted
1228+
1229+
yield {
1230+
"get_plan": mock_get_plan,
1231+
"count_tasks": mock_count_tasks,
1232+
"is_whitelisted": mock_is_whitelisted,
1233+
"add_job": mock_add_job,
1234+
"send_task": mock_send_task,
1235+
}
1236+
1237+
def test_create_newsletter_success_whitelisted(self, mock_dependencies):
1238+
"""Test successful newsletter creation for a whitelisted BETA user."""
1239+
jwt_token = generate_test_jwt(email="[email protected]", user_id="test_user_123")
1240+
1241+
response = client.post(
1242+
"/create-newsletter",
1243+
headers={"Authorization": f"Bearer {jwt_token}"},
1244+
json={
1245+
"prompt": "Weekly AI news",
1246+
"schedule": {
1247+
"type": "RECURRING_WEEKLY",
1248+
"recurring_weekly": {"days": ["friday"], "time": "10:00"},
1249+
},
1250+
},
1251+
)
1252+
assert response.status_code == 200
1253+
data = response.json()
1254+
assert data["is_scheduled"] is True
1255+
assert data["is_whitelisted"] is True
1256+
assert data["sample_email_sent"] is True
1257+
assert len(data["scheduled_task_ids"]) == 1
1258+
mock_dependencies["send_task"].assert_called_once()
1259+
1260+
def test_create_newsletter_task_limit_exceeded(self, mock_dependencies):
1261+
"""Test that newsletter creation fails if the task limit is reached."""
1262+
mock_dependencies["get_plan"].return_value = UserPlan.BETA
1263+
1264+
jwt_token = generate_test_jwt(email="[email protected]", user_id="test_user_123")
1265+
1266+
# Set current tasks to the max allowed for BETA plan using the config variable
1267+
mock_dependencies["count_tasks"].return_value = NEWSLETTER_LIMITS_BY_PLAN[UserPlan.BETA]["max_tasks"]
1268+
1269+
response = client.post(
1270+
"/create-newsletter",
1271+
headers={"Authorization": f"Bearer {jwt_token}"},
1272+
json={
1273+
"prompt": "Another newsletter",
1274+
"schedule": {
1275+
"type": "RECURRING_WEEKLY",
1276+
"recurring_weekly": {"days": ["monday"], "time": "08:00"},
1277+
},
1278+
},
1279+
)
1280+
assert response.status_code == 403
1281+
assert "Newsletter limit" in response.json()["detail"]
1282+
1283+
def test_create_newsletter_interval_too_frequent(self, mock_dependencies):
1284+
"""Test that creation fails if the cron interval is too short for the user's plan."""
1285+
mock_dependencies["get_plan"].return_value = UserPlan.BETA
1286+
1287+
jwt_token = generate_test_jwt(email="[email protected]", user_id="test_user_123")
1288+
1289+
response = client.post(
1290+
"/create-newsletter",
1291+
headers={"Authorization": f"Bearer {jwt_token}"},
1292+
json={
1293+
"prompt": "Daily newsletter",
1294+
"schedule": {
1295+
"type": "RECURRING_WEEKLY",
1296+
"recurring_weekly": {"days": ["monday", "tuesday"], "time": "07:00"},
1297+
},
1298+
},
1299+
)
1300+
assert response.status_code == 400
1301+
assert "Cron interval is too frequent" in response.json()["detail"]
1302+
1303+
def test_create_newsletter_not_whitelisted(self, mock_dependencies):
1304+
"""Test behavior for a non-whitelisted user."""
1305+
mock_dependencies["is_whitelisted"].return_value = (False, False)
1306+
jwt_token = generate_test_jwt(email="[email protected]", user_id="test_user_123")
1307+
1308+
with patch("mxgo.api.whitelist.trigger_automatic_verification", new_callable=AsyncMock) as mock_trigger_verify:
1309+
response = client.post(
1310+
"/create-newsletter",
1311+
headers={"Authorization": f"Bearer {jwt_token}"},
1312+
json={
1313+
"prompt": "A test newsletter",
1314+
"schedule": {
1315+
"type": "RECURRING_WEEKLY",
1316+
"recurring_weekly": {"days": ["saturday"], "time": "12:00"},
1317+
},
1318+
},
1319+
)
1320+
assert response.status_code == 200
1321+
data = response.json()
1322+
assert data["is_scheduled"] is True
1323+
assert data["is_whitelisted"] is False
1324+
assert data["sample_email_sent"] is False
1325+
mock_dependencies["send_task"].assert_not_called()
1326+
mock_trigger_verify.assert_called_once()

0 commit comments

Comments
 (0)