|
| 1 | +# Local Testing Guide for Kernelbot + Popcorn CLI |
| 2 | + |
| 3 | +This document describes how to set up and test the kernelbot API and popcorn-cli admin flow locally. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +### 1. PostgreSQL Setup |
| 8 | + |
| 9 | +Install and start PostgreSQL: |
| 10 | + |
| 11 | +```bash |
| 12 | +# Install PostgreSQL 14 via Homebrew |
| 13 | +brew install postgresql@14 |
| 14 | + |
| 15 | +# Start the service |
| 16 | +brew services start postgresql@14 |
| 17 | + |
| 18 | +# If brew services fails, start directly: |
| 19 | +/opt/homebrew/opt/postgresql@14/bin/pg_ctl -D /opt/homebrew/var/postgresql@14 start |
| 20 | +``` |
| 21 | + |
| 22 | +Create the kernelbot database: |
| 23 | + |
| 24 | +```bash |
| 25 | +# Replace YOUR_USERNAME with your system username |
| 26 | +psql -U YOUR_USERNAME -d postgres -c "CREATE DATABASE kernelbot;" |
| 27 | +``` |
| 28 | + |
| 29 | +### 2. Environment Variables |
| 30 | + |
| 31 | +Create a `.env` file in the kernelbot root directory: |
| 32 | + |
| 33 | +```bash |
| 34 | +# Required for API startup |
| 35 | +GITHUB_TOKEN=placeholder_github_token |
| 36 | +GITHUB_REPO=owner/kernelbot |
| 37 | + |
| 38 | +# Local PostgreSQL database (replace YOUR_USERNAME with your system username) |
| 39 | +DATABASE_URL=postgresql://YOUR_USERNAME@localhost:5432/kernelbot |
| 40 | +DISABLE_SSL=true |
| 41 | + |
| 42 | +# Admin token for local testing |
| 43 | +ADMIN_TOKEN=your_secure_token_here |
| 44 | + |
| 45 | +# Problem directory (absolute path to examples folder) |
| 46 | +PROBLEM_DEV_DIR=/path/to/kernelbot/examples |
| 47 | +``` |
| 48 | + |
| 49 | +### 3. Database Migrations |
| 50 | + |
| 51 | +Run yoyo migrations to set up the schema: |
| 52 | + |
| 53 | +```bash |
| 54 | +cd /path/to/kernelbot |
| 55 | +# Replace YOUR_USERNAME with your system username |
| 56 | +uv run yoyo apply --database "postgresql://YOUR_USERNAME@localhost:5432/kernelbot" src/migrations/ --batch |
| 57 | +``` |
| 58 | + |
| 59 | +If migrations fail due to partial application, mark them as applied: |
| 60 | + |
| 61 | +```bash |
| 62 | +# Replace YOUR_USERNAME with your system username |
| 63 | +uv run yoyo mark --all --database "postgresql://YOUR_USERNAME@localhost:5432/kernelbot" src/migrations/ --batch |
| 64 | +``` |
| 65 | + |
| 66 | +## Running Tests |
| 67 | + |
| 68 | +### Unit Tests (pytest) |
| 69 | + |
| 70 | +Run the admin API tests: |
| 71 | + |
| 72 | +```bash |
| 73 | +cd /path/to/kernelbot |
| 74 | +uv run pytest tests/test_admin_api.py -v |
| 75 | +``` |
| 76 | + |
| 77 | +Run all tests: |
| 78 | + |
| 79 | +```bash |
| 80 | +uv run pytest tests/ -v |
| 81 | +``` |
| 82 | + |
| 83 | +### Integration Tests with Docker |
| 84 | + |
| 85 | +The test suite uses docker-compose for database setup: |
| 86 | + |
| 87 | +```bash |
| 88 | +uv run pytest tests/ -v |
| 89 | +``` |
| 90 | + |
| 91 | +This automatically starts a test database container. |
| 92 | + |
| 93 | +## Starting the API |
| 94 | + |
| 95 | +### API-Only Mode (No Discord) |
| 96 | + |
| 97 | +Start the API server without requiring Discord credentials: |
| 98 | + |
| 99 | +```bash |
| 100 | +cd /path/to/kernelbot/src/kernelbot |
| 101 | +uv run python main.py --api-only |
| 102 | +``` |
| 103 | + |
| 104 | +The API will be available at `http://localhost:8000`. |
| 105 | + |
| 106 | +### Verify API is Running |
| 107 | + |
| 108 | +```bash |
| 109 | +curl http://localhost:8000/leaderboards |
| 110 | +# Should return: [] |
| 111 | +``` |
| 112 | + |
| 113 | +## Testing Admin Commands |
| 114 | + |
| 115 | +### Using curl |
| 116 | + |
| 117 | +```bash |
| 118 | +# Set your admin token |
| 119 | +TOKEN="your_secure_token_here" |
| 120 | + |
| 121 | +# Start accepting jobs |
| 122 | +curl -X POST http://localhost:8000/admin/start -H "Authorization: Bearer $TOKEN" |
| 123 | + |
| 124 | +# Get stats |
| 125 | +curl http://localhost:8000/admin/stats -H "Authorization: Bearer $TOKEN" |
| 126 | + |
| 127 | +# Stop accepting jobs |
| 128 | +curl -X POST http://localhost:8000/admin/stop -H "Authorization: Bearer $TOKEN" |
| 129 | +``` |
| 130 | + |
| 131 | +### Using Popcorn CLI |
| 132 | + |
| 133 | +First, build the CLI: |
| 134 | + |
| 135 | +```bash |
| 136 | +cd /path/to/popcorn-cli |
| 137 | +cargo build |
| 138 | +``` |
| 139 | + |
| 140 | +Then run admin commands: |
| 141 | + |
| 142 | +```bash |
| 143 | +# Set environment variables |
| 144 | +export POPCORN_API_URL=http://127.0.0.1:8000 |
| 145 | +export POPCORN_ADMIN_TOKEN=your_secure_token_here |
| 146 | + |
| 147 | +# IMPORTANT: If you have HTTP proxy set, bypass it for local testing |
| 148 | +unset HTTP_PROXY HTTPS_PROXY |
| 149 | + |
| 150 | +# Admin commands |
| 151 | +./target/debug/popcorn-cli admin start |
| 152 | +./target/debug/popcorn-cli admin stats |
| 153 | +./target/debug/popcorn-cli admin stop |
| 154 | +./target/debug/popcorn-cli admin get-submission 123 |
| 155 | +./target/debug/popcorn-cli admin delete-submission 123 |
| 156 | +./target/debug/popcorn-cli admin create-leaderboard identity_py |
| 157 | +./target/debug/popcorn-cli admin delete-leaderboard identity_py-dev |
| 158 | + |
| 159 | +# Update problems from reference-kernels repo (mirrors Discord /admin update-problems) |
| 160 | +./target/debug/popcorn-cli admin update-problems --problem-set nvidia |
| 161 | +./target/debug/popcorn-cli admin update-problems --problem-set pmpp_v2 --force |
| 162 | +./target/debug/popcorn-cli admin update-problems # Updates all problem sets |
| 163 | +``` |
| 164 | + |
| 165 | +## End-to-End CLI Testing |
| 166 | + |
| 167 | +Full workflow to test the admin CLI: |
| 168 | + |
| 169 | +```bash |
| 170 | +# 1. Start the API server (in kernelbot repo) |
| 171 | +cd /path/to/kernelbot/src/kernelbot |
| 172 | +ADMIN_TOKEN=test_token PROBLEM_DEV_DIR=/path/to/kernelbot/examples uv run python main.py --api-only |
| 173 | + |
| 174 | +# 2. In another terminal, set up CLI environment |
| 175 | +cd /path/to/popcorn-cli |
| 176 | +cargo build |
| 177 | +unset HTTP_PROXY HTTPS_PROXY |
| 178 | +export POPCORN_API_URL=http://127.0.0.1:8000 |
| 179 | +export POPCORN_ADMIN_TOKEN=test_token |
| 180 | + |
| 181 | +# 3. Test admin commands |
| 182 | +./target/debug/popcorn-cli admin start |
| 183 | +./target/debug/popcorn-cli admin stats |
| 184 | + |
| 185 | +# 4. Create and delete a leaderboard (name auto-derived as "{directory}-dev") |
| 186 | +./target/debug/popcorn-cli admin create-leaderboard identity_py |
| 187 | +curl -s http://127.0.0.1:8000/leaderboards | jq '.[].name' |
| 188 | +./target/debug/popcorn-cli admin delete-leaderboard identity_py-dev |
| 189 | +``` |
| 190 | + |
| 191 | +## Troubleshooting |
| 192 | + |
| 193 | +### "Connection refused" errors |
| 194 | + |
| 195 | +1. Check if API is running: `lsof -i :8000` |
| 196 | +2. Make sure you're using `127.0.0.1` instead of `localhost` (IPv6 issues) |
| 197 | +3. Check for HTTP proxy: `echo $HTTP_PROXY` - if set, unset it for local testing |
| 198 | + |
| 199 | +### "folly::AsyncSocketException" errors |
| 200 | + |
| 201 | +This indicates an HTTP proxy is intercepting requests. Fix: |
| 202 | + |
| 203 | +```bash |
| 204 | +unset HTTP_PROXY HTTPS_PROXY |
| 205 | +export NO_PROXY=127.0.0.1,localhost |
| 206 | +``` |
| 207 | + |
| 208 | +### Database connection errors |
| 209 | + |
| 210 | +1. Check PostgreSQL is running: `brew services list | grep postgres` |
| 211 | +2. Verify DATABASE_URL in .env matches your setup |
| 212 | +3. Check database exists: `psql -U YOUR_USERNAME -d kernelbot -c "SELECT 1;"` |
| 213 | + |
| 214 | +### "DISCORD_TOKEN not found" error |
| 215 | + |
| 216 | +Make sure you're using `--api-only` flag when starting the server. |
| 217 | + |
| 218 | +### Admin token errors |
| 219 | + |
| 220 | +- 401 "Missing Authorization header": Token not being sent |
| 221 | +- 401 "Invalid admin token": Token doesn't match ADMIN_TOKEN in .env |
| 222 | +- 500 "ADMIN_TOKEN not configured": Set ADMIN_TOKEN in .env |
| 223 | + |
| 224 | +## Architecture Notes |
| 225 | + |
| 226 | +### API-Only Mode |
| 227 | + |
| 228 | +The `--api-only` flag allows running the FastAPI server without Discord: |
| 229 | +- Skips Discord token validation |
| 230 | +- Creates backend without Discord bot initialization |
| 231 | +- All admin endpoints work via HTTP API |
| 232 | + |
| 233 | +### Admin Authentication |
| 234 | + |
| 235 | +Admin endpoints require: |
| 236 | +- Header: `Authorization: Bearer <ADMIN_TOKEN>` |
| 237 | +- Token is read from ADMIN_TOKEN environment variable |
| 238 | + |
| 239 | +### CLI Admin Commands |
| 240 | + |
| 241 | +The popcorn-cli admin commands use: |
| 242 | +- `POPCORN_API_URL`: API endpoint (default: production Heroku) |
| 243 | +- `POPCORN_ADMIN_TOKEN`: Bearer token for admin endpoints |
| 244 | + |
| 245 | +## Testing Against Production (Heroku) |
| 246 | + |
| 247 | +### Prerequisites |
| 248 | + |
| 249 | +1. Get the production admin token from Heroku config vars: |
| 250 | + ```bash |
| 251 | + heroku config:get ADMIN_TOKEN -a discord-cluster-manager |
| 252 | + ``` |
| 253 | + |
| 254 | +2. Or set it in Heroku if not already configured: |
| 255 | + ```bash |
| 256 | + heroku config:set ADMIN_TOKEN=your_secure_production_token -a discord-cluster-manager |
| 257 | + ``` |
| 258 | + |
| 259 | +3. If migrating from LOCAL_ADMIN_TOKEN: |
| 260 | + ```bash |
| 261 | + heroku config:set ADMIN_TOKEN=$(heroku config:get LOCAL_ADMIN_TOKEN -a discord-cluster-manager) -a discord-cluster-manager |
| 262 | + heroku config:unset LOCAL_ADMIN_TOKEN -a discord-cluster-manager |
| 263 | + ``` |
| 264 | + |
| 265 | +### Using CLI with Production |
| 266 | + |
| 267 | +```bash |
| 268 | +# Build CLI |
| 269 | +cd /path/to/popcorn-cli |
| 270 | +cargo build --release |
| 271 | + |
| 272 | +# Use production API (default URL) |
| 273 | +export POPCORN_ADMIN_TOKEN=<production_token_from_heroku> |
| 274 | + |
| 275 | +# Admin commands will hit production |
| 276 | +./target/release/popcorn-cli admin stats |
| 277 | +./target/release/popcorn-cli admin start |
| 278 | +./target/release/popcorn-cli admin stop |
| 279 | +``` |
| 280 | + |
| 281 | +### Using curl with Production |
| 282 | + |
| 283 | +```bash |
| 284 | +PROD_URL="https://discord-cluster-manager-1f6c4782e60a.herokuapp.com" |
| 285 | +PROD_TOKEN="<production_token_from_heroku>" |
| 286 | + |
| 287 | +# Get stats |
| 288 | +curl "$PROD_URL/admin/stats" -H "Authorization: Bearer $PROD_TOKEN" |
| 289 | + |
| 290 | +# Start/stop job acceptance |
| 291 | +curl -X POST "$PROD_URL/admin/start" -H "Authorization: Bearer $PROD_TOKEN" |
| 292 | +curl -X POST "$PROD_URL/admin/stop" -H "Authorization: Bearer $PROD_TOKEN" |
| 293 | +``` |
| 294 | + |
| 295 | +### Checking Heroku Logs |
| 296 | + |
| 297 | +```bash |
| 298 | +# View recent logs |
| 299 | +heroku logs --tail -a discord-cluster-manager |
| 300 | + |
| 301 | +# Filter for admin actions |
| 302 | +heroku logs -a discord-cluster-manager | grep admin |
| 303 | +``` |
| 304 | + |
| 305 | +### Production Environment Variables |
| 306 | + |
| 307 | +Required Heroku config vars for full functionality: |
| 308 | +- `DISCORD_TOKEN`: Discord bot token |
| 309 | +- `GITHUB_TOKEN`: GitHub API token |
| 310 | +- `GITHUB_REPO`: GitHub repository (e.g., `org/kernelbot`) |
| 311 | +- `DATABASE_URL`: PostgreSQL connection string (auto-set by Heroku Postgres) |
| 312 | +- `ADMIN_TOKEN`: Admin API authentication token |
| 313 | +- `MODAL_TOKEN_ID` / `MODAL_TOKEN_SECRET`: Modal credentials for GPU runs |
| 314 | + |
| 315 | +View all config vars: |
| 316 | +```bash |
| 317 | +heroku config -a discord-cluster-manager |
| 318 | +``` |
| 319 | + |
| 320 | +### Safety Notes for Production |
| 321 | + |
| 322 | +- Always test changes locally first before deploying to production |
| 323 | +- Admin commands affect live users - use `admin stop` carefully |
| 324 | +- Check stats before and after operations to verify expected behavior |
| 325 | +- Monitor Heroku logs when testing production changes |
0 commit comments