import json
import uuid
from datetime import datetime
from typing import Any, Dict, List, Optional
import requests
# Configuration
BASE_URL: str = "https://devrant.com/api"
RESULTS_FILE: str = "api_test_results.json"
APP: int = 3
PLAT: int = 3
GUID: str = str(uuid.uuid4())
SID: str = str(int(datetime.now().timestamp()))
SEID: str = str(uuid.uuid4())
# Real credentials for login (using provided username/email and password)
LOGIN_USERNAME: str = "power-to@the-puff.com"
LOGIN_PASSWORD: str = "powerpuffgirl"
# Variables to store auth after login
AUTH_TOKEN_ID: Optional[str] = None
AUTH_TOKEN_KEY: Optional[str] = None
AUTH_USER_ID: Optional[str] = None
# Mock/fallback values (overridden after login or fetch)
TEST_EMAIL: str = "test@example.com"
TEST_USERNAME: str = "testuser" + str(
int(datetime.now().timestamp())
) # Make unique for registration
TEST_PASSWORD: str = "Test1234!"
TEST_RANT_ID: str = "1" # Will be overridden with real one
TEST_COMMENT_ID: str = "1" # Will be overridden with real one
TEST_NEWS_ID: str = "1" # Assuming this might work; adjust if needed
# Initialize results
results: List[Dict[str, Any]] = []
def save_results() -> None:
"""Save the accumulated test results to JSON file."""
with open(RESULTS_FILE, "w") as f:
json.dump(results, f, indent=2)
def test_endpoint(
method: str,
url: str,
params: Optional[Dict[str, Any]] = None,
data: Optional[Dict[str, Any]] = None,
files: Optional[Dict[str, Any]] = None,
headers: Optional[Dict[str, str]] = None,
) -> Dict[str, Any]:
"""
Execute an API request and record the result.
Payload:
- method: HTTP method (GET, POST, DELETE, etc.)
- url: Full API URL
- params: Query parameters (dict)
- data: POST/PUT body (dict)
- files: Multipart files (dict)
- headers: Custom headers (dict)
Response:
- Returns a dict with url, method, status_code, response (JSON or error), headers, request_body, timestamp
"""
try:
response = requests.request(
method, url, params=params, data=data, files=files, headers=headers
)
result: Dict[str, Any] = {
"url": response.url,
"method": method,
"status_code": response.status_code,
"response": response.json() if response.content else {},
"headers": dict(response.headers),
"request_body": data or params or {},
"timestamp": datetime.now().isoformat(),
}
results.append(result)
return result
except Exception as e:
result: Dict[str, Any] = {
"url": url,
"method": method,
"status_code": None,
"response": {"error": str(e)},
"headers": {},
"request_body": data or params or {},
"timestamp": datetime.now().isoformat(),
}
results.append(result)
return result
# Helper to patch auth into params/data
def patch_auth(base_dict: Dict[str, Any]) -> Dict[str, Any]:
"""
Add authentication to request dict if available.
Payload: base_dict (params or data)
Response: Updated dict with app, user_id, token_id, token_key if auth present
"""
auth_dict: Dict[str, Any] = {"app": APP}
if AUTH_USER_ID and AUTH_TOKEN_ID and AUTH_TOKEN_KEY:
auth_dict.update(
{
"user_id": AUTH_USER_ID,
"token_id": AUTH_TOKEN_ID,
"token_key": AUTH_TOKEN_KEY,
}
)
base_dict.update(auth_dict)
return base_dict
# Login function to get real auth tokens
def login_user() -> bool:
"""
Perform login to obtain real auth tokens.
Payload: POST to /users/auth-token with username, password, app
Response: success (bool), sets global AUTH_* variables on success
"""
params: Dict[str, Any] = {
"username": LOGIN_USERNAME,
"password": LOGIN_PASSWORD,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
result = test_endpoint(
"POST", f"{BASE_URL}/users/auth-token", data=patch_auth(params)
)
if result["status_code"] == 200 and result.get("response", {}).get("success"):
auth_token = result["response"].get("auth_token", {})
global AUTH_USER_ID, AUTH_TOKEN_ID, AUTH_TOKEN_KEY
AUTH_USER_ID = str(auth_token.get("user_id", ""))
AUTH_TOKEN_ID = str(auth_token.get("id", ""))
AUTH_TOKEN_KEY = auth_token.get("key", "")
return True
return False
# Fetch a real rant_id from feed
def fetch_real_rant_id() -> Optional[str]:
"""
Fetch rants feed to get a real rant_id.
Payload: GET to /devrant/rants with auth
Response: First rant_id if success, else None
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
result = test_endpoint(
"GET", f"{BASE_URL}/devrant/rants", params=patch_auth(params)
)
if result["status_code"] == 200 and result.get("response", {}).get("success"):
rants = result["response"].get("rants", [])
if rants:
return str(rants[0]["id"])
return None
# Post a test rant and return its id
def post_test_rant() -> Optional[str]:
"""
Post a test rant to get a real rant_id for further tests.
Payload: POST to /devrant/rants with rant content, tags, auth
Response: rant_id if success, else None
"""
data: Dict[str, Any] = {
"rant": "Test rant for API testing (ignore)",
"tags": "test,api",
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
result = test_endpoint("POST", f"{BASE_URL}/devrant/rants", data=patch_auth(data))
if result["status_code"] == 200 and result.get("response", {}).get("success"):
return str(result["response"].get("rant_id", ""))
return None
# Post a test comment and return its id
def post_test_comment(rant_id: str) -> Optional[str]:
"""
Post a test comment to get a real comment_id.
Payload: POST to /devrant/rants/{rant_id}/comments with comment, auth
Response: comment_id if success, else None
"""
data: Dict[str, Any] = {
"comment": "Test comment for API testing (ignore)",
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
result = test_endpoint(
"POST", f"{BASE_URL}/devrant/rants/{rant_id}/comments", data=patch_auth(data)
)
if result["status_code"] == 200 and result.get("response", {}).get("success"):
return str(result["response"].get("comment_id", ""))
return None
# Test cases with docstrings
def test_register_user() -> None:
"""
Test user registration (valid and invalid).
Payload (valid): POST /users with email, username, password, type=1, plat, guid, sid, seid, app
Expected: success=true if unique, else error
Payload (invalid): Missing email
Expected: error on email field
"""
params: Dict[str, Any] = {
"type": 1,
"email": TEST_EMAIL,
"username": TEST_USERNAME,
"password": TEST_PASSWORD,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint("POST", f"{BASE_URL}/users", data=patch_auth(params.copy()))
invalid_params = params.copy()
del invalid_params["email"]
test_endpoint("POST", f"{BASE_URL}/users", data=patch_auth(invalid_params))
def test_login_user() -> None:
"""
Test user login (valid and invalid). Already done in login_user(), but record here.
Payload (valid): POST /users/auth-token with username, password, plat, guid, sid, seid, app
Expected: success=true, auth_token
Payload (invalid): Wrong password
Expected: error=Invalid login credentials
"""
# Valid is handled in login_user(); here test invalid
params: Dict[str, Any] = {
"username": TEST_USERNAME,
"password": "WrongPass",
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint("POST", f"{BASE_URL}/users/auth-token", data=patch_auth(params))
def test_edit_profile() -> None:
"""
Test editing user profile.
Payload: POST /users/me/edit-profile with profile fields, plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {
"profile_about": "Test bio",
"profile_skills": "Python, JS",
"profile_location": "Test City",
"profile_website": "http://example.com",
"profile_github": "testuser",
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint("POST", f"{BASE_URL}/users/me/edit-profile", data=patch_auth(params))
def test_forgot_password() -> None:
"""
Test forgot password.
Payload: POST /users/forgot-password with username, plat, guid, sid, seid, app
Expected: success=true (even without auth)
"""
params: Dict[str, Any] = {
"username": LOGIN_USERNAME, # Use real one
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint("POST", f"{BASE_URL}/users/forgot-password", data=patch_auth(params))
def test_resend_confirm() -> None:
"""
Test resend confirmation email.
Payload: POST /users/me/resend-confirm with plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
test_endpoint(
"POST", f"{BASE_URL}/users/me/resend-confirm", data=patch_auth(params)
)
def test_delete_account() -> None:
"""
Test delete account (caution: irreversible).
Payload: DELETE /users/me with plat, guid, sid, seid, auth
Expected: success=true
"""
# Comment out to avoid accidental deletion
# params: Dict[str, Any] = {
# "plat": PLAT,
# "guid": GUID,
# "sid": SID,
# "seid": SEID
# }
# test_endpoint("DELETE", f"{BASE_URL}/users/me", params=patch_auth(params))
pass
def test_mark_news_read() -> None:
"""
Test mark news as read.
Payload: POST /users/me/mark-news-read with news_id, plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {
"news_id": TEST_NEWS_ID,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint(
"POST", f"{BASE_URL}/users/me/mark-news-read", data=patch_auth(params)
)
def test_get_rant() -> None:
"""
Test get single rant.
Payload: GET /devrant/rants/{rant_id} with last_comment_id, links, plat, guid, sid, seid, auth
Expected: success=true, rant details
"""
params: Dict[str, Any] = {
"last_comment_id": "999999999999",
"links": 0,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint(
"GET", f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}", params=patch_auth(params)
)
def test_post_rant() -> None:
"""
Test post new rant. (Already done in post_test_rant for id)
Payload: POST /devrant/rants with rant, tags, auth
Expected: success=true, rant_id
"""
# Handled in setup
pass
def test_edit_rant() -> None:
"""
Test edit rant.
Payload: POST /devrant/rants/{rant_id} with updated rant, tags, auth
Expected: success=true
"""
data: Dict[str, Any] = {"rant": "Updated test rant", "tags": "test,python,update"}
test_endpoint(
"POST", f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}", data=patch_auth(data)
)
def test_delete_rant() -> None:
"""
Test delete rant.
Payload: DELETE /devrant/rants/{rant_id} with plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
test_endpoint(
"DELETE", f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}", params=patch_auth(params)
)
def test_vote_rant() -> None:
"""
Test vote on rant (upvote and downvote with reason).
Payload: POST /devrant/rants/{rant_id}/vote with vote (1/-1), reason (optional), plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {
"vote": 1,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint(
"POST", f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}/vote", data=patch_auth(params)
)
params["vote"] = -1
params["reason"] = "1"
test_endpoint(
"POST", f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}/vote", data=patch_auth(params)
)
def test_favorite_rant() -> None:
"""
Test favorite/unfavorite rant.
Payload: POST /devrant/rants/{rant_id}/favorite or /unfavorite with plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
test_endpoint(
"POST",
f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}/favorite",
data=patch_auth(params),
)
test_endpoint(
"POST",
f"{BASE_URL}/devrant/rants/{TEST_RANT_ID}/unfavorite",
data=patch_auth(params),
)
def test_get_rant_feed() -> None:
"""
Test get rant feed.
Payload: GET /devrant/rants with plat, guid, sid, seid, auth
Expected: success=true, list of rants
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
test_endpoint("GET", f"{BASE_URL}/devrant/rants", params=patch_auth(params))
def test_get_comment() -> None:
"""
Test get single comment.
Payload: GET /comments/{comment_id} with links, plat, guid, sid, seid, auth
Expected: success=true, comment details
"""
params: Dict[str, Any] = {
"links": 0,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint(
"GET", f"{BASE_URL}/comments/{TEST_COMMENT_ID}", params=patch_auth(params)
)
def test_post_comment() -> None:
"""
Test post comment. (Handled in post_test_comment for id)
Payload: POST /devrant/rants/{rant_id}/comments with comment, auth
Expected: success=true, comment_id
"""
# Handled in setup
pass
def test_edit_comment() -> None:
"""
Test edit comment.
Payload: POST /comments/{comment_id} with updated comment, auth
Expected: success=true
"""
data: Dict[str, Any] = {"comment": "Updated test comment"}
test_endpoint(
"POST", f"{BASE_URL}/comments/{TEST_COMMENT_ID}", data=patch_auth(data)
)
def test_delete_comment() -> None:
"""
Test delete comment.
Payload: DELETE /comments/{comment_id} with plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
test_endpoint(
"DELETE", f"{BASE_URL}/comments/{TEST_COMMENT_ID}", params=patch_auth(params)
)
def test_vote_comment() -> None:
"""
Test vote on comment.
Payload: POST /comments/{comment_id}/vote with vote (1), plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {
"vote": 1,
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint(
"POST", f"{BASE_URL}/comments/{TEST_COMMENT_ID}/vote", data=patch_auth(params)
)
def test_get_notif_feed() -> None:
"""
Test get notification feed.
Payload: GET /users/me/notif-feed with ext_prof, last_time, plat, guid, sid, seid, auth
Expected: success=true, notifications
"""
params: Dict[str, Any] = {
"ext_prof": 1,
"last_time": str(int(datetime.now().timestamp())),
"plat": PLAT,
"guid": GUID,
"sid": SID,
"seid": SEID,
}
test_endpoint("GET", f"{BASE_URL}/users/me/notif-feed", params=patch_auth(params))
def test_clear_notifications() -> None:
"""
Test clear notifications.
Payload: DELETE /users/me/notif-feed with plat, guid, sid, seid, auth
Expected: success=true
"""
params: Dict[str, Any] = {"plat": PLAT, "guid": GUID, "sid": SID, "seid": SEID}
test_endpoint(
"DELETE", f"{BASE_URL}/users/me/notif-feed", params=patch_auth(params)
)
def test_beta_list_signup() -> None:
"""
Test beta list signup (external API).
Payload: GET https://www.hexicallabs.com/api/beta-list with email, platform, app
Expected: Whatever the API returns (may not be JSON)
"""
params: Dict[str, Any] = {"email": TEST_EMAIL, "platform": "test_platform"}
test_endpoint(
"GET", "https://www.hexicallabs.com/api/beta-list", params=patch_auth(params)
)
def main() -> None:
# Setup: Login and fetch real IDs
if login_user():
global TEST_RANT_ID
TEST_RANT_ID = post_test_rant() or fetch_real_rant_id() or "1"
global TEST_COMMENT_ID
TEST_COMMENT_ID = post_test_comment(TEST_RANT_ID) or "1"
test_register_user()
test_login_user()
test_edit_profile()
test_forgot_password()
test_resend_confirm()
test_mark_news_read()
test_get_rant()
test_post_rant()
test_edit_rant()
test_vote_rant()
test_favorite_rant()
test_get_rant_feed()
test_get_comment()
test_post_comment()
test_edit_comment()
test_delete_comment()
test_vote_comment()
test_get_notif_feed()
test_clear_notifications()
test_beta_list_signup()
test_delete_rant()
test_delete_account()
save_results()
if __name__ == "__main__":
main()