import base64 import random import string from datetime import date, timedelta import requests from algosdk import account, mnemonic, util BASE_URL = "http://localhost:8000" REQ_TIMEOUT = 20 class SimpleResp: def __init__(self, status_code, text=""): self.status_code = status_code self.text = text def json(self): raise ValueError("no json body") def safe_request(method, url, **kwargs): if "timeout" not in kwargs: kwargs["timeout"] = REQ_TIMEOUT try: return requests.request(method, url, **kwargs) except Exception as exc: return SimpleResp(599, str(exc)) def parse_env(path): data = {} try: with open(path, "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line or line.startswith("#"): continue if "=" not in line: continue key, val = line.split("=", 1) key = key.strip() val = val.strip().strip("\"").strip("'") data[key] = val except FileNotFoundError: pass return data env = parse_env("/home/chidori/Projects/rift/backend/.env") platform_wallet = (env.get("PLATFORM_WALLET") or "").strip() algorand_mnemonic = (env.get("ALGORAND_MNEMONIC") or "").strip() def rand_name(prefix): return prefix + "_" + "".join(random.choices(string.ascii_lowercase + string.digits, k=6)) def issue_challenge(wallet_address): return safe_request("POST", f"{BASE_URL}/auth/challenge", json={"wallet_address": wallet_address}) def sign_message(private_key, message): sig = util.sign_bytes(message.encode("utf-8"), private_key) if isinstance(sig, str): sig = sig.encode("utf-8") return base64.b64encode(sig).decode("utf-8") def signup(wallet_address, private_key, username, role): chall = issue_challenge(wallet_address) if chall.status_code != 200: return None, chall try: message = chall.json()["message"] except Exception: return None, SimpleResp(599, "challenge missing json") signature = sign_message(private_key, message) payload = { "wallet_address": wallet_address, "signature": signature, "message": message, "username": username, "role": role, } res = safe_request("POST", f"{BASE_URL}/auth/signup", json=payload) return res, None def login(wallet_address, private_key): chall = issue_challenge(wallet_address) if chall.status_code != 200: return None, chall try: message = chall.json()["message"] except Exception: return None, SimpleResp(599, "challenge missing json") signature = sign_message(private_key, message) payload = { "wallet_address": wallet_address, "signature": signature, "message": message, } res = safe_request("POST", f"{BASE_URL}/auth/login", json=payload) return res, None def get_token_for_new_user(role): private_key, address = account.generate_account() username = rand_name(role) res, chall_err = signup(address, private_key, username, role) if chall_err is not None: return None, address, private_key, chall_err if res.status_code == 200: try: return res.json()["access_token"], address, private_key, None except Exception: return None, address, private_key, SimpleResp(599, "signup missing json") if res.status_code == 400 and "User already exists" in res.text: res2, chall_err2 = login(address, private_key) if chall_err2 is not None: return None, address, private_key, chall_err2 if res2.status_code == 200: try: return res2.json()["access_token"], address, private_key, None except Exception: return None, address, private_key, SimpleResp(599, "login missing json") return None, address, private_key, res2 return None, address, private_key, res results = [] def record(name, res, extra=None): if res is None: results.append((name, "SKIP", extra or "")) return status = "PASS" if res.status_code < 400 else "FAIL" detail = f"{res.status_code}" if res.status_code >= 400: detail += f" {res.text[:300]}" if extra: detail += f" | {extra}" results.append((name, status, detail)) record("GET /", safe_request("GET", f"{BASE_URL}/")) # Creator creator_token, creator_addr, creator_pk, err = get_token_for_new_user("creator") if not creator_token: if err is None: results.append(("creator token", "FAIL", "unknown error")) else: results.append(("creator token", "FAIL", f"{err.status_code} {err.text[:300]}")) else: headers_creator = {"Authorization": f"Bearer {creator_token}"} record("GET /auth/me", safe_request("GET", f"{BASE_URL}/auth/me", headers=headers_creator)) files = {"file": ("test_video.mp4", b"dummy_video_content_bytes", "video/mp4")} data = {"title": f"Test Video {rand_name('v')}", "description": "Automated test"} res_upload = safe_request("POST", f"{BASE_URL}/videos/upload", headers=headers_creator, files=files, data=data) record("POST /videos/upload", res_upload) video_id = None if res_upload.status_code == 200: try: video_id = res_upload.json().get("video_id") except Exception: video_id = None record("GET /videos/list", safe_request("GET", f"{BASE_URL}/videos/list")) record("GET /videos/me", safe_request("GET", f"{BASE_URL}/videos/me", headers=headers_creator)) if video_id: record("GET /videos/{id}", safe_request("GET", f"{BASE_URL}/videos/{video_id}")) if video_id: res_view = safe_request( "POST", f"{BASE_URL}/views/track", headers=headers_creator, json={"video_id": video_id, "watch_seconds": 30}, ) record("POST /views/track", res_view) record("GET /wallets/balance", safe_request("GET", f"{BASE_URL}/wallets/balance", headers=headers_creator)) # Advertiser advertiser_token, advertiser_addr, advertiser_pk, err = get_token_for_new_user("advertiser") if not advertiser_token: if err is None: results.append(("advertiser token", "FAIL", "unknown error")) else: results.append(("advertiser token", "FAIL", f"{err.status_code} {err.text[:300]}")) else: headers_ad = {"Authorization": f"Bearer {advertiser_token}"} record("GET /auth/me (advertiser)", safe_request("GET", f"{BASE_URL}/auth/me", headers=headers_ad)) if 'video_id' in locals() and video_id: res_campaign = safe_request( "POST", f"{BASE_URL}/ads/create", headers=headers_ad, data={"video_id": video_id, "budget": "100", "reward_per_view": "1"}, ) record("POST /ads/create", res_campaign) record("GET /ads/active", safe_request("GET", f"{BASE_URL}/ads/active")) record("GET /ads/me", safe_request("GET", f"{BASE_URL}/ads/me", headers=headers_ad)) record("GET /ads/summary", safe_request("GET", f"{BASE_URL}/ads/summary", headers=headers_ad)) start = date.today().isoformat() end = (date.today() + timedelta(days=1)).isoformat() res_banner = safe_request( "POST", f"{BASE_URL}/ads/banner/create", headers=headers_ad, data={"tier": "1m", "fixed_price": "25", "start_date": start, "end_date": end}, ) record("POST /ads/banner/create", res_banner) record("GET /ads/banner/active", safe_request("GET", f"{BASE_URL}/ads/banner/active")) record("GET /ads/banner/me", safe_request("GET", f"{BASE_URL}/ads/banner/me", headers=headers_ad)) # Settlement (public) record("GET /settlement/", safe_request("GET", f"{BASE_URL}/settlement/")) record("GET /settlement/summary", safe_request("GET", f"{BASE_URL}/settlement/summary")) # Platform-only platform_token = None platform_pk = None platform_addr = None if platform_wallet and algorand_mnemonic: try: platform_pk = mnemonic.to_private_key(algorand_mnemonic) platform_addr = account.address_from_private_key(platform_pk) if platform_addr == platform_wallet: res, err = signup(platform_addr, platform_pk, rand_name("platform"), "viewer") if err is None and res.status_code == 200: platform_token = res.json()["access_token"] else: res2, err2 = login(platform_addr, platform_pk) if err2 is None and res2.status_code == 200: platform_token = res2.json()["access_token"] else: results.append(("platform auth", "SKIP", "PLATFORM_WALLET does not match ALGORAND_MNEMONIC address")) except Exception as exc: results.append(("platform auth", "SKIP", f"error: {exc}")) else: results.append(("platform auth", "SKIP", "PLATFORM_WALLET or ALGORAND_MNEMONIC not set")) if platform_token: headers_platform = {"Authorization": f"Bearer {platform_token}"} record("GET /wallets/platform-balance", safe_request("GET", f"{BASE_URL}/wallets/platform-balance", headers=headers_platform)) record("POST /settlement/trigger", safe_request("POST", f"{BASE_URL}/settlement/trigger", headers=headers_platform)) record("POST /settlement/trigger-banner", safe_request("POST", f"{BASE_URL}/settlement/trigger-banner", headers=headers_platform)) else: record("GET /wallets/platform-balance", None, "no platform token") record("POST /settlement/trigger", None, "no platform token") record("POST /settlement/trigger-banner", None, "no platform token") print("\n=== Route Test Summary ===") for name, status, detail in results: print(f"{status:<5} {name} -> {detail}")