fixes for pytest
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,7 +1,8 @@
|
|||||||
from fastapi import status
|
from fastapi import status
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, timezone # Add timezone
|
||||||
|
from pytest_mock import MockerFixture # Import MockerFixture
|
||||||
|
|
||||||
from tests.helpers import generators
|
from tests.helpers import generators
|
||||||
from modules.calendar.models import CalendarEvent # Assuming model exists
|
from modules.calendar.models import CalendarEvent # Assuming model exists
|
||||||
@@ -10,13 +11,14 @@ from tests.conftest import fake
|
|||||||
|
|
||||||
# Helper function to create an event payload
|
# Helper function to create an event payload
|
||||||
def create_event_payload(start_offset_days=0, end_offset_days=1):
|
def create_event_payload(start_offset_days=0, end_offset_days=1):
|
||||||
start_time = datetime.utcnow() + timedelta(days=start_offset_days)
|
# Ensure datetimes are timezone-aware (UTC)
|
||||||
end_time = datetime.utcnow() + timedelta(days=end_offset_days)
|
start_time = datetime.now(timezone.utc) + timedelta(days=start_offset_days)
|
||||||
|
end_time = datetime.now(timezone.utc) + timedelta(days=end_offset_days)
|
||||||
return {
|
return {
|
||||||
"title": fake.sentence(nb_words=3),
|
"title": fake.sentence(nb_words=3),
|
||||||
"description": fake.text(),
|
"description": fake.text(),
|
||||||
"start": start_time.isoformat(), # Rename start_time to start
|
"start": start_time.isoformat().replace("+00:00", "Z"), # Ensure Z suffix
|
||||||
"end": end_time.isoformat(), # Rename end_time to end
|
"end": end_time.isoformat().replace("+00:00", "Z"), # Ensure Z suffix
|
||||||
"all_day": fake.boolean(),
|
"all_day": fake.boolean(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,13 +33,20 @@ def test_create_event_unauthorized(client: TestClient) -> None:
|
|||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
def test_create_event_success(db: Session, client: TestClient) -> None:
|
def test_create_event_success(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None:
|
||||||
"""Test creating a calendar event successfully."""
|
"""Test creating a calendar event successfully."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock the celery task sending
|
||||||
|
mock_send_task = mocker.patch(
|
||||||
|
"core.celery_app.celery_app.send_task"
|
||||||
|
) # Corrected patch target
|
||||||
|
|
||||||
response = client.post(
|
response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
@@ -49,7 +58,7 @@ def test_create_event_success(db: Session, client: TestClient) -> None:
|
|||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["title"] == payload["title"]
|
assert data["title"] == payload["title"]
|
||||||
assert data["description"] == payload["description"]
|
assert data["description"] == payload["description"]
|
||||||
# Remove the '+ "Z"' as the API doesn't add it
|
# Assert with Z suffix
|
||||||
assert data["start"] == payload["start"]
|
assert data["start"] == payload["start"]
|
||||||
assert data["end"] == payload["end"]
|
assert data["end"] == payload["end"]
|
||||||
assert data["all_day"] == payload["all_day"]
|
assert data["all_day"] == payload["all_day"]
|
||||||
@@ -62,6 +71,11 @@ def test_create_event_success(db: Session, client: TestClient) -> None:
|
|||||||
assert event_in_db.user_id == user.id
|
assert event_in_db.user_id == user.id
|
||||||
assert event_in_db.title == payload["title"]
|
assert event_in_db.title == payload["title"]
|
||||||
|
|
||||||
|
# Assert that the task was called correctly
|
||||||
|
mock_send_task.assert_called_once_with(
|
||||||
|
"modules.calendar.tasks.schedule_event_notifications", args=[data["id"]]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- Test Get Events ---
|
# --- Test Get Events ---
|
||||||
|
|
||||||
@@ -72,36 +86,49 @@ def test_get_events_unauthorized(client: TestClient) -> None:
|
|||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
def test_get_events_success(db: Session, client: TestClient) -> None:
|
def test_get_events_success(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test getting all calendar events for a user."""
|
"""Test getting all calendar events for a user."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(
|
||||||
|
db, username="testuser_get_events"
|
||||||
|
) # Unique username
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
# Create a couple of events for the user
|
# Create a couple of events for the user
|
||||||
payload1 = create_event_payload(0, 1)
|
payload1 = create_event_payload(0, 1)
|
||||||
client.post(
|
create_rsp1 = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload1,
|
json=payload1,
|
||||||
)
|
)
|
||||||
|
assert create_rsp1.status_code == status.HTTP_201_CREATED
|
||||||
|
|
||||||
payload2 = create_event_payload(2, 3)
|
payload2 = create_event_payload(2, 3)
|
||||||
client.post(
|
create_rsp2 = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload2,
|
json=payload2,
|
||||||
)
|
)
|
||||||
|
assert create_rsp2.status_code == status.HTTP_201_CREATED
|
||||||
|
|
||||||
# Create an event for another user (should not be returned)
|
# Create an event for another user (should not be returned)
|
||||||
other_user, other_password = generators.create_user(db)
|
other_user, other_password = generators.create_user(
|
||||||
|
db, username="otheruser_get_events"
|
||||||
|
) # Unique username
|
||||||
other_login_rsp = generators.login(db, other_user.username, other_password)
|
other_login_rsp = generators.login(db, other_user.username, other_password)
|
||||||
other_access_token = other_login_rsp["access_token"]
|
other_access_token = other_login_rsp["access_token"]
|
||||||
other_payload = create_event_payload(4, 5)
|
other_payload = create_event_payload(4, 5)
|
||||||
client.post(
|
create_rsp_other = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {other_access_token}"},
|
headers={"Authorization": f"Bearer {other_access_token}"},
|
||||||
json=other_payload,
|
json=other_payload,
|
||||||
)
|
)
|
||||||
|
assert create_rsp_other.status_code == status.HTTP_201_CREATED
|
||||||
|
|
||||||
response = client.get(
|
response = client.get(
|
||||||
"/api/calendar/events", headers={"Authorization": f"Bearer {access_token}"}
|
"/api/calendar/events", headers={"Authorization": f"Bearer {access_token}"}
|
||||||
@@ -115,35 +142,51 @@ def test_get_events_success(db: Session, client: TestClient) -> None:
|
|||||||
assert data[1]["user_id"] == user.id
|
assert data[1]["user_id"] == user.id
|
||||||
|
|
||||||
|
|
||||||
def test_get_events_filtered(db: Session, client: TestClient) -> None:
|
def test_get_events_filtered(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test getting filtered calendar events for a user."""
|
"""Test getting filtered calendar events for a user."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(
|
||||||
|
db, username="testuser_filter_events"
|
||||||
|
) # Unique username
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
# Create events
|
# Create events
|
||||||
payload1 = create_event_payload(0, 1) # Today -> Tomorrow
|
payload1 = create_event_payload(0, 1) # Today -> Tomorrow
|
||||||
client.post(
|
create_rsp1 = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload1,
|
json=payload1,
|
||||||
)
|
)
|
||||||
|
assert create_rsp1.status_code == status.HTTP_201_CREATED
|
||||||
|
|
||||||
payload2 = create_event_payload(5, 6) # In 5 days -> In 6 days
|
payload2 = create_event_payload(5, 6) # In 5 days -> In 6 days
|
||||||
client.post(
|
create_rsp2 = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload2,
|
json=payload2,
|
||||||
)
|
)
|
||||||
|
assert create_rsp2.status_code == status.HTTP_201_CREATED
|
||||||
|
|
||||||
payload3 = create_event_payload(10, 11) # In 10 days -> In 11 days
|
payload3 = create_event_payload(10, 11) # In 10 days -> In 11 days
|
||||||
client.post(
|
create_rsp3 = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload3,
|
json=payload3,
|
||||||
)
|
)
|
||||||
|
assert create_rsp3.status_code == status.HTTP_201_CREATED
|
||||||
|
|
||||||
# Filter for events starting within the next week
|
# Filter for events starting within the next week
|
||||||
start_filter = datetime.utcnow().isoformat()
|
start_filter = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
||||||
end_filter = (datetime.utcnow() + timedelta(days=7)).isoformat()
|
end_filter = (
|
||||||
|
(datetime.now(timezone.utc) + timedelta(days=7))
|
||||||
|
.isoformat()
|
||||||
|
.replace("+00:00", "Z")
|
||||||
|
)
|
||||||
|
|
||||||
response = client.get(
|
response = client.get(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
@@ -157,7 +200,11 @@ def test_get_events_filtered(db: Session, client: TestClient) -> None:
|
|||||||
assert data[1]["title"] == payload2["title"]
|
assert data[1]["title"] == payload2["title"]
|
||||||
|
|
||||||
# Filter for events starting after 8 days
|
# Filter for events starting after 8 days
|
||||||
start_filter_late = (datetime.utcnow() + timedelta(days=8)).isoformat()
|
start_filter_late = (
|
||||||
|
(datetime.now(timezone.utc) + timedelta(days=8))
|
||||||
|
.isoformat()
|
||||||
|
.replace("+00:00", "Z")
|
||||||
|
)
|
||||||
response = client.get(
|
response = client.get(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
@@ -172,34 +219,48 @@ def test_get_events_filtered(db: Session, client: TestClient) -> None:
|
|||||||
# --- Test Get Event By ID ---
|
# --- Test Get Event By ID ---
|
||||||
|
|
||||||
|
|
||||||
def test_get_event_by_id_unauthorized(db: Session, client: TestClient) -> None:
|
def test_get_event_by_id_unauthorized(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test getting a specific event without authentication."""
|
"""Test getting a specific event without authentication."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
|
|
||||||
response = client.get(f"/api/calendar/events/{event_id}")
|
response = client.get(f"/api/calendar/events/{event_id}")
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
def test_get_event_by_id_success(db: Session, client: TestClient) -> None:
|
def test_get_event_by_id_success(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test getting a specific event successfully."""
|
"""Test getting a specific event successfully."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
|
|
||||||
response = client.get(
|
response = client.get(
|
||||||
@@ -210,6 +271,9 @@ def test_get_event_by_id_success(db: Session, client: TestClient) -> None:
|
|||||||
data = response.json()
|
data = response.json()
|
||||||
assert data["id"] == event_id
|
assert data["id"] == event_id
|
||||||
assert data["title"] == payload["title"]
|
assert data["title"] == payload["title"]
|
||||||
|
# Assert datetime with Z suffix
|
||||||
|
assert data["start"] == payload["start"]
|
||||||
|
assert data["end"] == payload["end"]
|
||||||
assert data["user_id"] == user.id
|
assert data["user_id"] == user.id
|
||||||
|
|
||||||
|
|
||||||
@@ -227,20 +291,31 @@ def test_get_event_by_id_not_found(db: Session, client: TestClient) -> None:
|
|||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
def test_get_event_by_id_forbidden(db: Session, client: TestClient) -> None:
|
def test_get_event_by_id_forbidden(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test getting another user's event."""
|
"""Test getting another user's event."""
|
||||||
user1, password_user1 = generators.create_user(db)
|
user1, password_user1 = generators.create_user(
|
||||||
user2, password_user2 = generators.create_user(db)
|
db, username="user1_forbidden_get"
|
||||||
|
) # Unique username
|
||||||
|
user2, password_user2 = generators.create_user(
|
||||||
|
db, username="user2_forbidden_get"
|
||||||
|
) # Unique username
|
||||||
|
|
||||||
# Log in as user1 and create an event
|
# Log in as user1 and create an event
|
||||||
login_rsp1 = generators.login(db, user1.username, password_user1)
|
login_rsp1 = generators.login(db, user1.username, password_user1)
|
||||||
access_token1 = login_rsp1["access_token"]
|
access_token1 = login_rsp1["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token1}"},
|
headers={"Authorization": f"Bearer {access_token1}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
|
|
||||||
# Log in as user2 and try to get user1's event
|
# Log in as user2 and try to get user1's event
|
||||||
@@ -259,17 +334,24 @@ def test_get_event_by_id_forbidden(db: Session, client: TestClient) -> None:
|
|||||||
# --- Test Update Event ---
|
# --- Test Update Event ---
|
||||||
|
|
||||||
|
|
||||||
def test_update_event_unauthorized(db: Session, client: TestClient) -> None:
|
def test_update_event_unauthorized(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test updating an event without authentication."""
|
"""Test updating an event without authentication."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
update_payload = {"title": "Updated Title"}
|
update_payload = {"title": "Updated Title"}
|
||||||
|
|
||||||
@@ -277,12 +359,20 @@ def test_update_event_unauthorized(db: Session, client: TestClient) -> None:
|
|||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
def test_update_event_success(db: Session, client: TestClient) -> None:
|
def test_update_event_success(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test updating an event successfully."""
|
"""Test updating an event successfully."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch(
|
||||||
|
"core.celery_app.celery_app.send_task", return_value=None
|
||||||
|
) # Mock for creation
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
@@ -299,6 +389,13 @@ def test_update_event_success(db: Session, client: TestClient) -> None:
|
|||||||
"all_day": not payload["all_day"], # Toggle all_day
|
"all_day": not payload["all_day"], # Toggle all_day
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Mock celery task for update (needs separate mock)
|
||||||
|
mock_send_task_update = mocker.patch(
|
||||||
|
"modules.calendar.service.celery_app.send_task"
|
||||||
|
)
|
||||||
|
# Mock cancel notifications as well, as it's called synchronously in the service
|
||||||
|
mocker.patch("modules.calendar.tasks.cancel_event_notifications")
|
||||||
|
|
||||||
response = client.patch(
|
response = client.patch(
|
||||||
f"/api/calendar/events/{event_id}",
|
f"/api/calendar/events/{event_id}",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
@@ -310,7 +407,8 @@ def test_update_event_success(db: Session, client: TestClient) -> None:
|
|||||||
assert data["title"] == update_payload["title"]
|
assert data["title"] == update_payload["title"]
|
||||||
assert data["description"] == update_payload["description"]
|
assert data["description"] == update_payload["description"]
|
||||||
assert data["all_day"] == update_payload["all_day"]
|
assert data["all_day"] == update_payload["all_day"]
|
||||||
assert data["start"] == payload["start"] # Check correct field name 'start'
|
# Assert datetime with Z suffix
|
||||||
|
assert data["start"] == payload["start"]
|
||||||
assert data["user_id"] == user.id
|
assert data["user_id"] == user.id
|
||||||
|
|
||||||
# Verify in DB
|
# Verify in DB
|
||||||
@@ -320,6 +418,17 @@ def test_update_event_success(db: Session, client: TestClient) -> None:
|
|||||||
assert event_in_db.description == update_payload["description"]
|
assert event_in_db.description == update_payload["description"]
|
||||||
assert event_in_db.all_day == update_payload["all_day"]
|
assert event_in_db.all_day == update_payload["all_day"]
|
||||||
|
|
||||||
|
# Assert that the update task was called correctly
|
||||||
|
mock_send_task_update.assert_called_once_with(
|
||||||
|
"modules.calendar.tasks.schedule_event_notifications", args=[event_id]
|
||||||
|
)
|
||||||
|
# Assert cancel was NOT called because update doesn't cancel
|
||||||
|
# mock_cancel_notifications.assert_not_called() # Update: cancel IS called in update path via re-schedule
|
||||||
|
# Actually, schedule_event_notifications calls cancel_event_notifications first.
|
||||||
|
# So we need to mock cancel_event_notifications called *within* schedule_event_notifications
|
||||||
|
# OR mock schedule_event_notifications itself. Let's stick to mocking send_task.
|
||||||
|
# The cancel mock added earlier handles the direct call in the service layer if any.
|
||||||
|
|
||||||
|
|
||||||
def test_update_event_not_found(db: Session, client: TestClient) -> None:
|
def test_update_event_not_found(db: Session, client: TestClient) -> None:
|
||||||
"""Test updating a non-existent event."""
|
"""Test updating a non-existent event."""
|
||||||
@@ -337,20 +446,31 @@ def test_update_event_not_found(db: Session, client: TestClient) -> None:
|
|||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
def test_update_event_forbidden(db: Session, client: TestClient) -> None:
|
def test_update_event_forbidden(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test updating another user's event."""
|
"""Test updating another user's event."""
|
||||||
user1, password_user1 = generators.create_user(db)
|
user1, password_user1 = generators.create_user(
|
||||||
user2, password_user2 = generators.create_user(db)
|
db, username="user1_forbidden_update"
|
||||||
|
) # Unique username
|
||||||
|
user2, password_user2 = generators.create_user(
|
||||||
|
db, username="user2_forbidden_update"
|
||||||
|
) # Unique username
|
||||||
|
|
||||||
# Log in as user1 and create an event
|
# Log in as user1 and create an event
|
||||||
login_rsp1 = generators.login(db, user1.username, password_user1)
|
login_rsp1 = generators.login(db, user1.username, password_user1)
|
||||||
access_token1 = login_rsp1["access_token"]
|
access_token1 = login_rsp1["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token1}"},
|
headers={"Authorization": f"Bearer {access_token1}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
|
|
||||||
# Log in as user2 and try to update user1's event
|
# Log in as user2 and try to update user1's event
|
||||||
@@ -371,29 +491,42 @@ def test_update_event_forbidden(db: Session, client: TestClient) -> None:
|
|||||||
# --- Test Delete Event ---
|
# --- Test Delete Event ---
|
||||||
|
|
||||||
|
|
||||||
def test_delete_event_unauthorized(db: Session, client: TestClient) -> None:
|
def test_delete_event_unauthorized(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test deleting an event without authentication."""
|
"""Test deleting an event without authentication."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
|
|
||||||
response = client.delete(f"/api/calendar/events/{event_id}")
|
response = client.delete(f"/api/calendar/events/{event_id}")
|
||||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||||
|
|
||||||
|
|
||||||
def test_delete_event_success(db: Session, client: TestClient) -> None:
|
def test_delete_event_success(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None:
|
||||||
"""Test deleting an event successfully."""
|
"""Test deleting an event successfully."""
|
||||||
user, password = generators.create_user(db)
|
user, password = generators.create_user(db)
|
||||||
login_rsp = generators.login(db, user.username, password)
|
login_rsp = generators.login(db, user.username, password)
|
||||||
access_token = login_rsp["access_token"]
|
access_token = login_rsp["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock the celery task sending for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
@@ -408,12 +541,20 @@ def test_delete_event_success(db: Session, client: TestClient) -> None:
|
|||||||
event_in_db = db.query(CalendarEvent).filter(CalendarEvent.id == event_id).first()
|
event_in_db = db.query(CalendarEvent).filter(CalendarEvent.id == event_id).first()
|
||||||
assert event_in_db is not None
|
assert event_in_db is not None
|
||||||
|
|
||||||
|
# Mock the cancel_event_notifications function to prevent Redis call
|
||||||
|
mock_cancel_notifications = mocker.patch(
|
||||||
|
"modules.calendar.service.cancel_event_notifications" # Target the function as used in service.py
|
||||||
|
)
|
||||||
|
|
||||||
response = client.delete(
|
response = client.delete(
|
||||||
f"/api/calendar/events/{event_id}",
|
f"/api/calendar/events/{event_id}",
|
||||||
headers={"Authorization": f"Bearer {access_token}"},
|
headers={"Authorization": f"Bearer {access_token}"},
|
||||||
)
|
)
|
||||||
assert response.status_code == status.HTTP_204_NO_CONTENT
|
assert response.status_code == status.HTTP_204_NO_CONTENT
|
||||||
|
|
||||||
|
# Assert that cancel_event_notifications was called
|
||||||
|
mock_cancel_notifications.assert_called_once_with(event_id)
|
||||||
|
|
||||||
# Verify event is deleted from DB
|
# Verify event is deleted from DB
|
||||||
event_in_db = db.query(CalendarEvent).filter(CalendarEvent.id == event_id).first()
|
event_in_db = db.query(CalendarEvent).filter(CalendarEvent.id == event_id).first()
|
||||||
assert event_in_db is None
|
assert event_in_db is None
|
||||||
@@ -441,20 +582,31 @@ def test_delete_event_not_found(db: Session, client: TestClient) -> None:
|
|||||||
assert response.status_code == status.HTTP_404_NOT_FOUND
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
def test_delete_event_forbidden(db: Session, client: TestClient) -> None:
|
def test_delete_event_forbidden(
|
||||||
|
db: Session, client: TestClient, mocker: MockerFixture
|
||||||
|
) -> None: # Add mocker
|
||||||
"""Test deleting another user's event."""
|
"""Test deleting another user's event."""
|
||||||
user1, password_user1 = generators.create_user(db)
|
user1, password_user1 = generators.create_user(
|
||||||
user2, password_user2 = generators.create_user(db)
|
db, username="user1_forbidden_delete"
|
||||||
|
) # Unique username
|
||||||
|
user2, password_user2 = generators.create_user(
|
||||||
|
db, username="user2_forbidden_delete"
|
||||||
|
) # Unique username
|
||||||
|
|
||||||
# Log in as user1 and create an event
|
# Log in as user1 and create an event
|
||||||
login_rsp1 = generators.login(db, user1.username, password_user1)
|
login_rsp1 = generators.login(db, user1.username, password_user1)
|
||||||
access_token1 = login_rsp1["access_token"]
|
access_token1 = login_rsp1["access_token"]
|
||||||
payload = create_event_payload()
|
payload = create_event_payload()
|
||||||
|
|
||||||
|
# Mock celery task for creation
|
||||||
|
mocker.patch("core.celery_app.celery_app.send_task")
|
||||||
|
|
||||||
create_response = client.post(
|
create_response = client.post(
|
||||||
"/api/calendar/events",
|
"/api/calendar/events",
|
||||||
headers={"Authorization": f"Bearer {access_token1}"},
|
headers={"Authorization": f"Bearer {access_token1}"},
|
||||||
json=payload,
|
json=payload,
|
||||||
)
|
)
|
||||||
|
assert create_response.status_code == status.HTTP_201_CREATED
|
||||||
event_id = create_response.json()["id"]
|
event_id = create_response.json()["id"]
|
||||||
|
|
||||||
# Log in as user2 and try to delete user1's event
|
# Log in as user2 and try to delete user1's event
|
||||||
|
|||||||
Reference in New Issue
Block a user