Skip to content

Commit 832f005

Browse files
aKhalid1476Abdullah KhalidAbdullah KhalidAbdullah KhalidAbdullah Khalid
authored
implemented everything on mcc command endpoints from before, but on a… (#589)
… new branch to fix yml file intervening push # Purpose Closes #351 Explain the purpose of the PR here if it doesn't match the linked issue. Be sure to add a comment in the linked issue explaining the changes. # New Changes Delete and post endpoints were created. # Testing Explain tests that you ran to verify code functionality. - Pytest is not working for FastAPI as of right now, so I instead created some python scripts which tested the mcc command endpoints. --------- Co-authored-by: Abdullah Khalid <abdullahkhalid@eduroam-campus-10-36-123-158.campus-dynamic.uwaterloo.ca> Co-authored-by: Abdullah Khalid <abdullahkhalid@eduroam-campus-10-36-28-190.campus-dynamic.uwaterloo.ca> Co-authored-by: Abdullah Khalid <abdullahkhalid@eduroam-campus-10-36-10-129.campus-dynamic.uwaterloo.ca> Co-authored-by: Abdullah Khalid <abdullahkhalid@Abdullahs-MacBook-Pro.local> Co-authored-by: Edison Wang <ew040607@gmail.com>
1 parent c46f415 commit 832f005

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,35 @@
1+
from typing import Any
2+
from uuid import UUID
3+
14
from fastapi import APIRouter
25

6+
from gs.backend.data.data_wrappers.mcc_wrappers.commands_wrapper import (
7+
create_commands,
8+
delete_commands_by_id,
9+
)
10+
from gs.backend.data.tables.transactional_tables import Commands
11+
312
commands_router = APIRouter(tags=["MCC", "Commands"])
13+
14+
15+
@commands_router.post("/create")
16+
async def create_command(payload: dict[str, Any]) -> Commands:
17+
"""
18+
Create a new command.
19+
20+
:param payload: The data used to create a command
21+
:return: returns the created command object
22+
"""
23+
return create_commands(payload)
24+
25+
26+
@commands_router.delete("/delete/{command_id}")
27+
async def delete_command(command_id: UUID) -> dict[str, Any]:
28+
"""
29+
Delete a command by ID.
30+
31+
:param command_id: The id which is to be deleted.
32+
:return: returns a dict giving confirmation that command with id of command_id has been deleted.
33+
"""
34+
delete_commands_by_id(command_id)
35+
return {"message": f"Command with id {command_id} deleted successfully"}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
from uuid import UUID, uuid4
2+
3+
import pytest
4+
from fastapi.testclient import TestClient
5+
from gs.backend.data.enums.transactional import CommandStatus
6+
from gs.backend.data.tables.main_tables import MainCommand
7+
from gs.backend.main import app
8+
9+
10+
@pytest.fixture
11+
def client():
12+
return TestClient(app)
13+
14+
15+
@pytest.fixture(autouse=True)
16+
def setup_main_commands(db_session):
17+
"""Setup MainCommand records needed for testing"""
18+
# Create MainCommand entries that will be referenced by Commands
19+
main_commands = [
20+
MainCommand(id=1, name="TestCmd1", params=None, format=None, data_size=4, total_size=4),
21+
MainCommand(id=2, name="TestCmd2", params=None, format=None, data_size=4, total_size=4),
22+
MainCommand(id=3, name="TestCmd3", params=None, format=None, data_size=4, total_size=4),
23+
MainCommand(id=4, name="TestCmd4", params=None, format=None, data_size=4, total_size=4),
24+
MainCommand(id=5, name="TestCmd5", params=None, format=None, data_size=4, total_size=4),
25+
MainCommand(id=6, name="TestCmd6", params=None, format=None, data_size=4, total_size=4),
26+
MainCommand(id=10, name="TestCmd10", params=None, format=None, data_size=4, total_size=4),
27+
MainCommand(id=11, name="TestCmd11", params=None, format=None, data_size=4, total_size=4),
28+
]
29+
for cmd in main_commands:
30+
db_session.add(cmd)
31+
db_session.commit()
32+
33+
34+
# ---------------------------------------------Testing the POST endpoint--------------------------------------------- #
35+
36+
37+
def test_create_command_success(client):
38+
"""Test successful creation of a new command"""
39+
payload = {
40+
"status": CommandStatus.PENDING,
41+
"type_": 1, # Assuming valid MainCommand ID
42+
"params": "test_params",
43+
}
44+
45+
response = client.post("/api/v1/mcc/commands/create", json=payload)
46+
47+
assert response.status_code == 200
48+
data = response.json()
49+
assert "id" in data
50+
assert data["status"] == CommandStatus.PENDING
51+
assert data["type_"] == 1
52+
assert data["params"] == "test_params"
53+
# Validate that id is a valid UUID
54+
UUID(data["id"])
55+
56+
57+
def test_create_command_duplicate(client):
58+
"""Test that creating a duplicate command is allowed and succeeds"""
59+
payload = {"status": CommandStatus.PENDING, "type_": 2, "params": "duplicate_test"}
60+
61+
# Create the first command
62+
response1 = client.post("/api/v1/mcc/commands/create", json=payload)
63+
assert response1.status_code == 200
64+
command1_id = response1.json()["id"]
65+
66+
# Create duplicate command (same payload except id will be different)
67+
response2 = client.post("/api/v1/mcc/commands/create", json=payload)
68+
assert response2.status_code == 200
69+
command2_id = response2.json()["id"]
70+
71+
# Both commands should exist but have different IDs
72+
assert command1_id != command2_id
73+
assert response2.json()["status"] == CommandStatus.PENDING
74+
assert response2.json()["type_"] == 2
75+
assert response2.json()["params"] == "duplicate_test"
76+
77+
78+
def test_create_command_with_null_params(client):
79+
"""Test creating a command with null params"""
80+
payload = {"status": CommandStatus.SCHEDULED, "type_": 3, "params": None}
81+
82+
response = client.post("/api/v1/mcc/commands/create", json=payload)
83+
84+
assert response.status_code == 200
85+
data = response.json()
86+
assert data["params"] is None
87+
assert data["status"] == CommandStatus.SCHEDULED
88+
89+
90+
def test_create_command_different_status(client):
91+
"""Test creating commands with different status values"""
92+
statuses = [CommandStatus.PENDING, CommandStatus.SCHEDULED, CommandStatus.SENT]
93+
94+
for idx, status in enumerate(statuses):
95+
payload = {
96+
"status": status,
97+
"type_": 4 + idx, # Use different type_ to avoid duplicates
98+
"params": f"params_{status}",
99+
}
100+
101+
response = client.post("/api/v1/mcc/commands/create", json=payload)
102+
assert response.status_code == 200
103+
assert response.json()["status"] == status
104+
105+
106+
# ---------------------------------------------Testing the DELETE endpoint--------------------------------------------- #
107+
108+
109+
def test_delete_command_success(client):
110+
"""Test successful deletion of an existing command"""
111+
# First create a command to delete
112+
payload = {"status": CommandStatus.PENDING, "type_": 10, "params": "to_be_deleted"}
113+
114+
create_response = client.post("/api/v1/mcc/commands/create", json=payload)
115+
assert create_response.status_code == 200
116+
command_id = create_response.json()["id"]
117+
118+
# Delete the command
119+
delete_response = client.delete(f"/api/v1/mcc/commands/delete/{command_id}")
120+
121+
assert delete_response.status_code == 200
122+
data = delete_response.json()
123+
assert data["message"] == f"Command with id {command_id} deleted successfully"
124+
125+
126+
def test_delete_command_not_found(client):
127+
"""Test deleting a non-existent command raises ValueError (unhandled exception)"""
128+
# Generate a random UUID that doesn't exist
129+
non_existent_id = uuid4()
130+
131+
# The endpoint raises ValueError which is not caught by FastAPI
132+
# This causes the test client to raise an exception
133+
with pytest.raises(ValueError, match="Command not found."):
134+
client.delete(f"/api/v1/mcc/commands/delete/{non_existent_id}")
135+
136+
137+
def test_delete_command_invalid_uuid(client):
138+
"""Test deleting with an invalid UUID format returns 422 error"""
139+
invalid_uuid = "not-a-valid-uuid"
140+
141+
response = client.delete(f"/api/v1/mcc/commands/delete/{invalid_uuid}")
142+
143+
# FastAPI validation error for invalid UUID format
144+
assert response.status_code == 422
145+
146+
147+
def test_delete_command_twice(client):
148+
"""Test that deleting the same command twice fails on second attempt"""
149+
# Create a command
150+
payload = {"status": CommandStatus.PENDING, "type_": 11, "params": "delete_twice_test"}
151+
152+
create_response = client.post("/api/v1/mcc/commands/create", json=payload)
153+
command_id = create_response.json()["id"]
154+
155+
# First deletion should succeed
156+
delete_response1 = client.delete(f"/api/v1/mcc/commands/delete/{command_id}")
157+
assert delete_response1.status_code == 200
158+
159+
# Second deletion should raise ValueError
160+
with pytest.raises(ValueError, match="Command not found."):
161+
client.delete(f"/api/v1/mcc/commands/delete/{command_id}")

0 commit comments

Comments
 (0)