# Comprehensive Testing Guide for Gitea v1.26.0 ## All Features to Test | Phase | Feature | Risk | Priority | |-------|---------|------|----------| | **1** | Request ID Tracing | Low | Medium | | **1** | Rate Limit Headers | Low | Medium | | **1** | Chunk Checksum Verification | Medium | High | | **1** | RFC 7807 Error Responses | Low | Medium | | **2** | V2 API Framework | Medium | High | | **2** | Structured Error Codes | Low | Medium | | **2** | Scalar API Docs | Low | Low | | **2** | Batch Operations | Medium | High | | **2** | NDJSON Streaming | Medium | High | | **2** | AI Context Endpoints | Low | Medium | | **3** | Operation Progress (SSE) | Medium | High | | **3** | Idempotency Middleware | High | Critical | | **3** | Webhook Retry | Medium | High | | **3** | Circuit Breaker | Medium | High | | **4** | CLI Tool (gitea-cli) | Low | Medium | | **4** | Go SDK | Low | Medium | | **4** | Python SDK | Low | Medium | | **4** | TypeScript SDK | Low | Medium | | **4** | C# SDK | Low | Medium | | **4** | Java SDK | Low | Medium | | **5** | Organization Pinned Repos | Low | Medium | | **5** | Organization Public Members | Low | Medium | | **5** | Gitea Pages | Medium | High | | **5** | Wiki V2 API | Medium | High | --- ## 1. Test Environment Setup ### Docker Test Instance ```bash mkdir gitea-test && cd gitea-test cat > docker-compose.yml << 'EOF' version: "3" services: gitea: image: gitea/gitea:1.26.0 container_name: gitea-test environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=sqlite3 - GITEA__server__ROOT_URL=http://localhost:3000/ volumes: - ./gitea-data:/data ports: - "3000:3000" - "2222:22" EOF docker-compose up -d ``` --- ## 2. Phase 1: API Reliability Enhancements ### 2.1 Request ID Tracing ```bash # Test auto-generated request ID curl -i http://localhost:3000/api/v1/version # Should see: X-Request-ID: # Test custom request ID passed through curl -i -H "X-Request-ID: my-custom-id-123" http://localhost:3000/api/v1/version # Should see: X-Request-ID: my-custom-id-123 # Test request ID in error responses curl -i http://localhost:3000/api/v1/repos/nonexistent/nonexistent # Error JSON should contain request_id field ``` **Checklist:** - [ ] X-Request-ID header present in all responses - [ ] Custom X-Request-ID passed through unchanged - [ ] Request ID included in error response body - [ ] Request ID appears in server logs ### 2.2 Rate Limit Headers ```bash # Check rate limit headers curl -i -H "Authorization: token $TOKEN" http://localhost:3000/api/v1/user # Should see: # X-RateLimit-Limit: # X-RateLimit-Remaining: # X-RateLimit-Reset: ``` **Checklist:** - [ ] Rate limit headers present on authenticated requests - [ ] Remaining count decrements - [ ] Reset timestamp is in the future ### 2.3 Chunk Checksum Verification ```bash # Create a test file echo "test content" > testfile.txt CHECKSUM=$(sha256sum testfile.txt | cut -d' ' -f1) # Upload with correct checksum (should succeed) curl -X POST \ -H "Authorization: token $TOKEN" \ -H "X-Chunk-Checksum: sha256=$CHECKSUM" \ -F "file=@testfile.txt" \ "http://localhost:3000/api/v1/repos/owner/repo/releases/1/assets" # Upload with wrong checksum (should fail) curl -X POST \ -H "Authorization: token $TOKEN" \ -H "X-Chunk-Checksum: sha256=wrongchecksum123" \ -F "file=@testfile.txt" \ "http://localhost:3000/api/v1/repos/owner/repo/releases/1/assets" # Should return 400 with checksum mismatch error ``` **Checklist:** - [ ] Upload succeeds with correct checksum - [ ] Upload fails with incorrect checksum - [ ] Upload succeeds without checksum header (optional) - [ ] Error message indicates checksum mismatch ### 2.4 RFC 7807 Error Responses ```bash # Trigger a 404 error curl -s http://localhost:3000/api/v1/repos/nonexistent/nonexistent | jq . ``` **Expected Response:** ```json { "type": "https://gitea.io/api/errors/not-found", "title": "Not Found", "status": 404, "detail": "Repository not found", "instance": "/api/v1/repos/nonexistent/nonexistent", "request_id": "abc123", "message": "Repository not found", "url": "https://gitea.io/api/errors/not-found" } ``` **Checklist:** - [ ] Error responses include `type`, `title`, `status`, `detail` - [ ] Legacy fields (`message`, `url`) still present for compatibility - [ ] `request_id` included in errors --- ## 3. Phase 2: V2 API with AI Features ### 3.1 V2 API Framework ```bash # Test v2 version endpoint curl http://localhost:3000/api/v2/version # Test v2 user endpoint (requires auth) curl -H "Authorization: token $TOKEN" http://localhost:3000/api/v2/user ``` **Checklist:** - [ ] V2 endpoints respond at `/api/v2/` - [ ] V1 endpoints still work at `/api/v1/` - [ ] Authentication works on v2 ### 3.2 Scalar API Documentation ```bash # Open in browser open http://localhost:3000/api/v2/docs # Fetch OpenAPI spec curl http://localhost:3000/api/v2/swagger.json ``` **Checklist:** - [ ] Scalar docs page loads - [ ] All v2 endpoints documented - [ ] "Try it" functionality works ### 3.3 Batch Operations ```bash # Batch get files curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "requests": [ {"owner": "org", "repo": "repo1", "path": "README.md", "ref": "main"}, {"owner": "org", "repo": "repo1", "path": "go.mod", "ref": "main"}, {"owner": "org", "repo": "repo2", "path": "package.json", "ref": "main"} ] }' \ http://localhost:3000/api/v2/batch/files # Batch get repos curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "repos": [ {"owner": "org", "repo": "repo1"}, {"owner": "org", "repo": "repo2"}, {"owner": "org", "repo": "repo3"} ] }' \ http://localhost:3000/api/v2/batch/repos ``` **Checklist:** - [ ] Batch files returns multiple file contents - [ ] Batch repos returns multiple repo details - [ ] Partial failures handled gracefully (some succeed, some fail) - [ ] Performance better than individual requests ### 3.4 NDJSON Streaming ```bash # Stream files curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/x-ndjson" \ -d '{"owner": "org", "repo": "repo", "paths": ["file1.go", "file2.go"]}' \ http://localhost:3000/api/v2/stream/files # Stream commits curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/x-ndjson" \ -d '{"owner": "org", "repo": "repo", "ref": "main", "limit": 100}' \ http://localhost:3000/api/v2/stream/commits # Stream issues curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -H "Accept: application/x-ndjson" \ -d '{"owner": "org", "repo": "repo", "state": "open"}' \ http://localhost:3000/api/v2/stream/issues ``` **Checklist:** - [ ] Responses are newline-delimited JSON - [ ] Each line is valid JSON - [ ] Streaming starts before all data is ready - [ ] Large datasets don't timeout ### 3.5 AI Context Endpoints ```bash # Repository summary curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"owner": "org", "repo": "repo"}' \ http://localhost:3000/api/v2/ai/repo/summary # Navigation hints curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"owner": "org", "repo": "repo"}' \ http://localhost:3000/api/v2/ai/repo/navigation # Issue context curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"owner": "org", "repo": "repo", "issue_number": 1}' \ http://localhost:3000/api/v2/ai/issue/context ``` **Checklist:** - [ ] Repo summary includes structure, languages, recent activity - [ ] Navigation includes important paths, file types - [ ] Issue context includes comments, labels, code references - [ ] AI hints provided (project type, suggested files) --- ## 4. Phase 3: Reliability Patterns ### 4.1 Operation Progress (SSE) ```bash # Start a long operation that returns operation ID OPERATION_ID=$(curl -X POST \ -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/repos/owner/repo/mirror-sync" | jq -r '.operation_id') # Subscribe to progress updates (SSE) curl -N -H "Accept: text/event-stream" \ "http://localhost:3000/api/v2/operations/$OPERATION_ID/progress" # Check operation status curl "http://localhost:3000/api/v2/operations/$OPERATION_ID" # Cancel operation curl -X DELETE "http://localhost:3000/api/v2/operations/$OPERATION_ID" ``` **Checklist:** - [ ] Operation ID returned from long-running endpoints - [ ] SSE stream provides real-time updates - [ ] Progress includes phase, percentage, ETA - [ ] Completed operations can be queried - [ ] Operations can be cancelled ### 4.2 Idempotency Middleware ```bash # First request - should execute curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Idempotency-Key: unique-key-123" \ -H "Content-Type: application/json" \ -d '{"title": "Test Issue", "body": "Test body"}' \ http://localhost:3000/api/v1/repos/owner/repo/issues # Duplicate request - should return cached response curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Idempotency-Key: unique-key-123" \ -H "Content-Type: application/json" \ -d '{"title": "Test Issue", "body": "Test body"}' \ http://localhost:3000/api/v1/repos/owner/repo/issues # Should see header: Idempotency-Replayed: true # Should NOT create duplicate issue ``` **Checklist:** - [ ] First request executes normally - [ ] Duplicate request returns cached response - [ ] `Idempotency-Replayed: true` header on cached responses - [ ] Different idempotency keys execute separately - [ ] Keys expire after 24 hours ### 4.3 Webhook Retry ```bash # Configure a webhook to a non-responsive endpoint # Trigger an event (push, issue create, etc.) # Check webhook delivery logs curl -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/repos/owner/repo/hooks/1/deliveries" ``` **Checklist:** - [ ] Failed deliveries are retried - [ ] Exponential backoff between retries - [ ] Max retries respected - [ ] Delivery attempts logged - [ ] Eventually marked as failed after max retries ### 4.4 Circuit Breaker ```bash # This is internal - check via metrics or logs # Simulate external service failure # Verify circuit opens after threshold # Verify circuit half-opens after timeout # Verify circuit closes after success ``` **Checklist:** - [ ] Circuit opens after consecutive failures - [ ] Requests fail fast when circuit open - [ ] Circuit transitions to half-open after timeout - [ ] Successful request closes circuit - [ ] Circuit state visible in health endpoint --- ## 5. Phase 4: SDK and CLI Tools ### 5.1 CLI Tool (gitea-cli) ```bash # Build CLI cd cmd/gitea-cli && go build -o gitea-cli . # Login ./gitea-cli auth login --server http://localhost:3000 --token $TOKEN # Check auth status ./gitea-cli auth status # Upload release asset ./gitea-cli upload release-asset \ --owner myorg \ --repo myrepo \ --release-id 1 \ --file ./large-file.zip # List pending uploads ./gitea-cli upload list # Resume interrupted upload ./gitea-cli upload resume --session-id # Logout ./gitea-cli auth logout ``` **Checklist:** - [ ] Login stores credentials securely - [ ] Upload shows progress bar - [ ] Chunked upload works for large files - [ ] Resume works after interruption - [ ] Checksum verification passes ### 5.2 Go SDK ```go package main import ( "fmt" gitea "code.gitea.io/gitea/sdk/go" ) func main() { client := gitea.NewClient("http://localhost:3000", "your-token") // Get user user, err := client.GetCurrentUser() if err != nil { panic(err) } fmt.Printf("Logged in as: %s\n", user.UserName) // Upload file with progress err = client.UploadReleaseAsset( "owner", "repo", 1, "./large-file.zip", gitea.WithProgress(func(current, total int64) { fmt.Printf("\rProgress: %d/%d", current, total) }), ) } ``` **Checklist:** - [ ] Client initializes with token - [ ] Basic API calls work - [ ] Chunked upload works - [ ] Progress callback fires - [ ] Errors properly typed ### 5.3 Python SDK ```python from gitea_sdk import GiteaClient client = GiteaClient("http://localhost:3000", token="your-token") # Get user user = client.get_current_user() print(f"Logged in as: {user.username}") # Upload with progress def on_progress(current, total): print(f"\rProgress: {current}/{total}", end="") client.upload_release_asset( owner="myorg", repo="myrepo", release_id=1, file_path="./large-file.zip", on_progress=on_progress ) ``` **Checklist:** - [ ] pip install works - [ ] Client connects with token - [ ] Basic API calls work - [ ] Type hints work in IDE - [ ] Chunked upload works ### 5.4 TypeScript SDK ```typescript import { GiteaClient } from '@gitea/sdk'; const client = new GiteaClient({ baseUrl: 'http://localhost:3000', token: 'your-token' }); // Get user const user = await client.getCurrentUser(); console.log(`Logged in as: ${user.username}`); // Upload with progress await client.uploadReleaseAsset({ owner: 'myorg', repo: 'myrepo', releaseId: 1, file: fs.createReadStream('./large-file.zip'), onProgress: (current, total) => { console.log(`Progress: ${current}/${total}`); } }); ``` **Checklist:** - [ ] npm install works - [ ] TypeScript types correct - [ ] Works in Node.js - [ ] Works in browser (where applicable) - [ ] Async/await works properly ### 5.5 C# SDK ```csharp using Gitea.SDK; var client = new GiteaClient("http://localhost:3000", "your-token"); // Get user var user = await client.GetCurrentUserAsync(); Console.WriteLine($"Logged in as: {user.UserName}"); // Upload with progress await client.UploadReleaseAssetAsync( owner: "myorg", repo: "myrepo", releaseId: 1, filePath: "./large-file.zip", onProgress: (current, total) => { Console.WriteLine($"Progress: {current}/{total}"); } ); ``` **Checklist:** - [ ] NuGet package installs - [ ] .NET 6+ compatible - [ ] Async methods work - [ ] Progress events fire - [ ] Proper disposal (IDisposable) ### 5.6 Java SDK ```java import io.gitea.sdk.GiteaClient; GiteaClient client = new GiteaClient("http://localhost:3000", "your-token"); // Get user User user = client.getCurrentUser(); System.out.println("Logged in as: " + user.getUserName()); // Upload with progress client.uploadReleaseAsset( "myorg", "myrepo", 1, new File("./large-file.zip"), (current, total) -> { System.out.printf("Progress: %d/%d%n", current, total); } ); ``` **Checklist:** - [ ] Maven/Gradle dependency works - [ ] Java 11+ compatible - [ ] Fluent API works - [ ] Progress callback fires - [ ] Proper resource management --- ## 6. Phase 5: Organization Profiles ### 6.1 Pinned Repositories ```bash # List pinned repos curl -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/orgs/myorg/pinned" # Pin a repository curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"repo_name": "my-repo"}' \ "http://localhost:3000/api/v1/orgs/myorg/pinned" # Create a pinned group curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Core Projects"}' \ "http://localhost:3000/api/v1/orgs/myorg/pinned/groups" # Add repo to group curl -X PUT \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"group_id": 1}' \ "http://localhost:3000/api/v1/orgs/myorg/pinned/my-repo" # Reorder pinned repos curl -X PUT \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"order": ["repo1", "repo2", "repo3"]}' \ "http://localhost:3000/api/v1/orgs/myorg/pinned/reorder" # Unpin repository curl -X DELETE \ -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/orgs/myorg/pinned/my-repo" ``` **Web UI Checklist:** - [ ] Pinned repos appear on org profile page - [ ] Groups are collapsible - [ ] Repo cards show stars, forks, language - [ ] Reordering works via drag-and-drop (if implemented) ### 6.2 Public Members ```bash # List public members with roles curl "http://localhost:3000/api/v1/orgs/myorg/public_members/roles" # Make yourself public curl -X PUT \ -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/orgs/myorg/public_members/myusername" # Remove public visibility curl -X DELETE \ -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/orgs/myorg/public_members/myusername" ``` **Checklist:** - [ ] Public members shown on org profile - [ ] Roles displayed (Owner, Admin, Member) - [ ] "and X more" overflow works - [ ] Opt-in/opt-out works --- ## 7. Phase 5: Gitea Pages ### 7.1 Basic Pages Setup ```bash # Create test repo with landing.yaml mkdir test-pages && cd test-pages git init cat > .gitea/landing.yaml << 'EOF' enabled: true template: simple branding: primary_color: "#4a90d9" hero: title: "My Project" tagline: "The best project ever" EOF cat > README.md << 'EOF' # My Project Welcome to my project! ## Features - Feature 1 - Feature 2 EOF git add -A && git commit -m "Initial commit" git push origin main ``` ### 7.2 Pages API ```bash # Get pages config curl -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/repos/owner/repo/pages" # Enable pages curl -X PUT \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"enabled": true, "template": "simple"}' \ "http://localhost:3000/api/v1/repos/owner/repo/pages" # Add custom domain curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"domain": "myproject.example.com"}' \ "http://localhost:3000/api/v1/repos/owner/repo/pages/domains" # Verify domain curl -X POST \ -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/repos/owner/repo/pages/domains/myproject.example.com/verify" # Disable pages curl -X DELETE \ -H "Authorization: token $TOKEN" \ "http://localhost:3000/api/v1/repos/owner/repo/pages" ``` ### 7.3 Template Testing Test each template by visiting `http://localhost:3000/owner/repo/pages`: **Simple Template:** - [ ] Hero section displays - [ ] README content renders - [ ] Repo stats shown in footer **Documentation Template:** - [ ] Sidebar navigation works - [ ] `/docs` folder content loads - [ ] Search works (if enabled) - [ ] "Edit this page" links work **Product Template:** - [ ] Hero with background - [ ] Features grid displays - [ ] Screenshot section works - [ ] Releases section shows latest **Portfolio Template:** - [ ] Gallery grid displays - [ ] Lightbox works on click - [ ] Captions display --- ## 8. Phase 5: Wiki V2 API ### 8.1 CRUD Operations ```bash BASE="http://localhost:3000/api/v2/repos/owner/repo/wiki" # List pages curl -H "Authorization: token $TOKEN" "$BASE/pages" # Get single page curl -H "Authorization: token $TOKEN" "$BASE/pages/Home" # Create page curl -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name": "Test-Page", "content": "# Test\n\nContent here."}' \ "$BASE/pages" # Update page curl -X PUT \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"content": "# Updated\n\nNew content."}' \ "$BASE/pages/Test-Page" # Rename page curl -X PUT \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"rename_to": "New-Page-Name"}' \ "$BASE/pages/Test-Page" # Delete page curl -X DELETE \ -H "Authorization: token $TOKEN" \ "$BASE/pages/New-Page-Name" ``` ### 8.2 Search, Graph, Stats ```bash # Search curl -H "Authorization: token $TOKEN" "$BASE/search?q=installation" # Link graph curl -H "Authorization: token $TOKEN" "$BASE/graph" # Statistics curl -H "Authorization: token $TOKEN" "$BASE/stats" # Page revisions curl -H "Authorization: token $TOKEN" "$BASE/pages/Home/revisions" ``` ### 8.3 Response Validation **Page Response Should Include:** - [ ] `content` - raw markdown - [ ] `content_html` - rendered HTML - [ ] `links_out` - outgoing wiki links - [ ] `links_in` - incoming links - [ ] `word_count` - accurate count - [ ] `last_commit` - author, date, message **Stats Response Should Include:** - [ ] `total_pages` - [ ] `total_words` - [ ] `health.orphaned_pages` - [ ] `health.dead_links` - [ ] `health.outdated_pages` - [ ] `health.short_pages` - [ ] `top_linked` --- ## 9. Regression Testing ### Critical Existing Features These MUST still work: ```bash # Repository clone git clone http://localhost:3000/owner/repo.git # Push git push origin main # V1 API still works curl http://localhost:3000/api/v1/version curl -H "Authorization: token $TOKEN" http://localhost:3000/api/v1/user curl http://localhost:3000/api/v1/repos/owner/repo # Wiki V1 still works curl http://localhost:3000/api/v1/repos/owner/repo/wiki/pages curl http://localhost:3000/api/v1/repos/owner/repo/wiki/page/Home # Issues curl http://localhost:3000/api/v1/repos/owner/repo/issues # Pull requests curl http://localhost:3000/api/v1/repos/owner/repo/pulls ``` **Checklist:** - [ ] Git clone (HTTP) - [ ] Git clone (SSH) - [ ] Git push - [ ] Branch creation - [ ] Tag creation - [ ] Pull request creation - [ ] Pull request merge - [ ] Issue creation - [ ] Wiki (web UI) - [ ] Wiki (V1 API) - [ ] User login - [ ] Organization operations --- ## 10. Complete Smoke Test Script ```bash #!/bin/bash set -e BASE="${GITEA_URL:-http://localhost:3000}" TOKEN="${GITEA_TOKEN:-your-token}" OWNER="${TEST_OWNER:-testorg}" REPO="${TEST_REPO:-testrepo}" RED='\033[0;31m' GREEN='\033[0;32m' NC='\033[0m' pass() { echo -e "${GREEN}✓${NC} $1"; } fail() { echo -e "${RED}✗${NC} $1"; FAILED=1; } test_endpoint() { local name=$1 local method=${2:-GET} local url=$3 local data=$4 if [ -n "$data" ]; then response=$(curl -sf -X $method -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" -d "$data" "$url" 2>/dev/null) && pass "$name" || fail "$name" else response=$(curl -sf -X $method -H "Authorization: token $TOKEN" "$url" 2>/dev/null) && pass "$name" || fail "$name" fi } echo "=== Gitea v1.26.0 Comprehensive Smoke Tests ===" echo "" echo "--- Phase 1: API Reliability ---" test_endpoint "Version endpoint" GET "$BASE/api/v1/version" test_endpoint "Request ID header" GET "$BASE/api/v1/version" echo "" echo "--- Phase 2: V2 API ---" test_endpoint "V2 Version" GET "$BASE/api/v2/version" test_endpoint "V2 User" GET "$BASE/api/v2/user" test_endpoint "V2 Docs" GET "$BASE/api/v2/docs" test_endpoint "V2 Batch Files" POST "$BASE/api/v2/batch/files" '{"requests":[]}' test_endpoint "V2 AI Repo Summary" POST "$BASE/api/v2/ai/repo/summary" "{\"owner\":\"$OWNER\",\"repo\":\"$REPO\"}" echo "" echo "--- Phase 3: Reliability ---" test_endpoint "Health Check" GET "$BASE/api/v2/health" echo "" echo "--- Phase 5: Org Profiles ---" test_endpoint "Org Pinned Repos" GET "$BASE/api/v1/orgs/$OWNER/pinned" test_endpoint "Org Public Members" GET "$BASE/api/v1/orgs/$OWNER/public_members/roles" echo "" echo "--- Phase 5: Pages ---" test_endpoint "Pages Config" GET "$BASE/api/v1/repos/$OWNER/$REPO/pages" echo "" echo "--- Phase 5: Wiki V2 ---" test_endpoint "Wiki List Pages" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/pages" test_endpoint "Wiki Search" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/search?q=test" test_endpoint "Wiki Graph" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/graph" test_endpoint "Wiki Stats" GET "$BASE/api/v2/repos/$OWNER/$REPO/wiki/stats" echo "" echo "--- Regression: V1 API ---" test_endpoint "V1 User" GET "$BASE/api/v1/user" test_endpoint "V1 Repos" GET "$BASE/api/v1/repos/$OWNER/$REPO" test_endpoint "V1 Wiki Pages" GET "$BASE/api/v1/repos/$OWNER/$REPO/wiki/pages" echo "" if [ -z "$FAILED" ]; then echo -e "${GREEN}All tests passed!${NC}" exit 0 else echo -e "${RED}Some tests failed!${NC}" exit 1 fi ``` Save as `smoke-test.sh` and run: ```bash chmod +x smoke-test.sh GITEA_URL=http://localhost:3000 GITEA_TOKEN=your-token ./smoke-test.sh ``` --- ## 11. Rollback Plan If any issues are found: ```bash # 1. Stop current version docker-compose down # 2. Restore previous version docker pull gitea/gitea:1.25.3 # 3. Update docker-compose.yml to use 1.25.3 # 4. Start previous version docker-compose up -d ``` **Safe to rollback because:** - New tables (wiki_index, pages_*, org_pinned_*) are ignored by old version - No existing tables were modified - V1 API unchanged - No data migration required --- ## Summary **Testing Priority:** 1. **Critical:** Idempotency, chunked uploads, V1 API regression 2. **High:** V2 batch/streaming, wiki V2 CRUD, pages rendering 3. **Medium:** SDKs, CLI, org profiles, operation progress 4. **Low:** Scalar docs, AI context endpoints **Recommended Testing Time:** - Automated tests: 30 minutes - Manual testing: 2-4 hours - Staging soak test: 24-48 hours - Total: 2-3 days before production