From b8b276fa05c2d6c2b6344cc22dfc4712fe9dfbd4 Mon Sep 17 00:00:00 2001 From: logikonline Date: Fri, 9 Jan 2026 15:24:40 -0500 Subject: [PATCH] docs: comprehensive testing guide covering all 5 phases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated testing guide now covers: Phase 1: API Reliability - Request ID tracing - Rate limit headers - Chunk checksum verification - RFC 7807 error responses Phase 2: V2 API - V2 framework - Scalar docs - Batch operations - NDJSON streaming - AI context endpoints Phase 3: Reliability Patterns - Operation progress (SSE) - Idempotency middleware - Webhook retry - Circuit breaker Phase 4: SDK & CLI - gitea-cli tool - Go, Python, TypeScript, C#, Java SDKs Phase 5: New Features - Organization pinned repos - Public members - Gitea Pages (4 templates) - Wiki V2 API Also includes: - Complete smoke test script - Regression testing checklist - Rollback plan 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- docs/testing-guide-v1.26.md | 1271 ++++++++++++++++++++++++----------- 1 file changed, 886 insertions(+), 385 deletions(-) diff --git a/docs/testing-guide-v1.26.md b/docs/testing-guide-v1.26.md index dcef35181a..e6b02226af 100644 --- a/docs/testing-guide-v1.26.md +++ b/docs/testing-guide-v1.26.md @@ -1,23 +1,43 @@ -# Testing Guide for Gitea v1.26.0 +# Comprehensive Testing Guide for Gitea v1.26.0 -## Overview +## All Features to Test -This guide covers testing the new features in v1.26.0 before production deployment: -- Phase 3: Organization Public Profile -- Phase 4: Gitea Pages -- Phase 5: Wiki V2 API +| 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 -### Option A: Docker Test Instance +### Docker Test Instance ```bash -# Create isolated test environment mkdir gitea-test && cd gitea-test -# Create docker-compose.yml cat > docker-compose.yml << 'EOF' version: "3" services: @@ -36,164 +56,712 @@ services: - "2222:22" EOF -# Start test instance docker-compose up -d - -# View logs -docker-compose logs -f gitea -``` - -### Option B: Local Binary Test - -```bash -# Build with test tags -make build TAGS="bindata sqlite sqlite_unlock_notify" - -# Create test directory -mkdir -p /tmp/gitea-test/{data,repos,log} - -# Run with test config -./gitea web --config /tmp/gitea-test/app.ini -``` - -### Test Database - -For testing, use SQLite to avoid affecting production databases: - -```ini -# /tmp/gitea-test/app.ini -[database] -DB_TYPE = sqlite3 -PATH = /tmp/gitea-test/data/gitea.db ``` --- -## 2. Automated Tests +## 2. Phase 1: API Reliability Enhancements -### Run Existing Test Suite +### 2.1 Request ID Tracing ```bash -# Unit tests -make test +# Test auto-generated request ID +curl -i http://localhost:3000/api/v1/version +# Should see: X-Request-ID: -# Integration tests (requires test database) -make test-sqlite +# 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 -# Specific package tests -go test -v ./services/wiki/... -go test -v ./models/repo/... -go test -v ./routers/api/v2/... +# Test request ID in error responses +curl -i http://localhost:3000/api/v1/repos/nonexistent/nonexistent +# Error JSON should contain request_id field ``` -### New Test Files to Create +**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 -#### Wiki V2 API Tests +### 2.2 Rate Limit Headers -```go -// routers/api/v2/wiki_test.go -package v2 +```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: +``` -import ( - "net/http" - "testing" +**Checklist:** +- [ ] Rate limit headers present on authenticated requests +- [ ] Remaining count decrements +- [ ] Reset timestamp is in the future - "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/tests" -) +### 2.3 Chunk Checksum Verification -func TestWikiV2API(t *testing.T) { - defer tests.PrepareTestEnv(t)() +```bash +# Create a test file +echo "test content" > testfile.txt +CHECKSUM=$(sha256sum testfile.txt | cut -d' ' -f1) - // Test list pages - t.Run("ListPages", func(t *testing.T) { - req := NewRequest(t, "GET", "/api/v2/repos/user2/repo1/wiki/pages") - resp := MakeRequest(t, req, http.StatusOK) - // Assert response structure - }) +# 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" - // Test create page - t.Run("CreatePage", func(t *testing.T) { - req := NewRequestWithJSON(t, "POST", "/api/v2/repos/user2/repo1/wiki/pages", map[string]string{ - "name": "Test-Page", - "content": "# Test\n\nThis is a test page.", - }) - AddTokenAuth(req, "user2") - resp := MakeRequest(t, req, http.StatusOK) - // Assert page created - }) +# 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 +``` - // Test search - t.Run("Search", func(t *testing.T) { - req := NewRequest(t, "GET", "/api/v2/repos/user2/repo1/wiki/search?q=test") - resp := MakeRequest(t, req, http.StatusOK) - // Assert search results - }) +**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. Manual Testing Checklist +## 3. Phase 2: V2 API with AI Features -### Phase 3: Organization Profile +### 3.1 V2 API Framework -#### Setup -- [ ] Create test organization: `test-org` -- [ ] Create 5+ test repositories in the organization -- [ ] Add 3+ members with different roles (Owner, Admin, Member) - -#### Pinned Repositories -- [ ] Pin a repository via API: `POST /api/v1/orgs/test-org/pinned` -- [ ] Verify pinned repo appears on org profile page -- [ ] Create a pinned group: `POST /api/v1/orgs/test-org/pinned/groups` -- [ ] Add repos to the group -- [ ] Reorder pinned repos via API -- [ ] Unpin a repository -- [ ] Delete a pinned group - -#### Public Members -- [ ] Set member as public via API -- [ ] Verify member appears on org profile -- [ ] Check role display (Owner/Admin/Member) -- [ ] Remove public visibility -- [ ] Verify "and X more" overflow works - -### Phase 4: Gitea Pages - -#### Setup -- [ ] Create test repository: `test-org/pages-test` -- [ ] Add `.gitea/landing.yaml` configuration file -- [ ] Add README.md with content - -#### Templates -- [ ] Test Simple template -- [ ] Test Documentation template (add `/docs` folder) -- [ ] Test Product template (add features config) -- [ ] Test Portfolio template (add `/gallery` folder) - -#### Settings UI -- [ ] Navigate to repo Settings → Pages -- [ ] Enable pages -- [ ] Select different templates -- [ ] Verify landing page renders at `/{owner}/{repo}/pages` - -#### Custom Domains (if configured) -- [ ] Add custom domain via API -- [ ] Check verification token generated -- [ ] Test domain verification flow - -### Phase 5: Wiki V2 API - -#### Setup -- [ ] Create test repository with wiki enabled -- [ ] Create initial wiki pages via web UI - -#### CRUD Operations ```bash -# Set variables -TOKEN="your-test-token" -BASE="http://localhost:3000/api/v2/repos/test-org/test-repo/wiki" +# 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" @@ -202,289 +770,198 @@ curl -H "Authorization: token $TOKEN" "$BASE/pages" curl -H "Authorization: token $TOKEN" "$BASE/pages/Home" # Create page -curl -X POST -H "Authorization: token $TOKEN" \ +curl -X POST \ + -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"name":"Test-Page","content":"# Test\n\nContent here."}' \ + -d '{"name": "Test-Page", "content": "# Test\n\nContent here."}' \ "$BASE/pages" # Update page -curl -X PUT -H "Authorization: token $TOKEN" \ +curl -X PUT \ + -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ - -d '{"content":"# Updated\n\nNew content."}' \ + -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/Test-Page" +curl -X DELETE \ + -H "Authorization: token $TOKEN" \ + "$BASE/pages/New-Page-Name" ``` -#### Search +### 8.2 Search, Graph, Stats + ```bash -# Search wiki +# Search curl -H "Authorization: token $TOKEN" "$BASE/search?q=installation" -``` -#### Graph & Stats -```bash -# Get link graph +# Link graph curl -H "Authorization: token $TOKEN" "$BASE/graph" -# Get statistics +# Statistics curl -H "Authorization: token $TOKEN" "$BASE/stats" + +# Page revisions +curl -H "Authorization: token $TOKEN" "$BASE/pages/Home/revisions" ``` -#### Verify Response Structure -- [ ] `content` field contains raw markdown -- [ ] `content_html` field contains rendered HTML -- [ ] `links_out` contains outgoing wiki links -- [ ] `links_in` contains incoming links -- [ ] `word_count` is accurate -- [ ] `last_commit` has correct author info +### 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` --- -## 4. Regression Testing +## 9. Regression Testing -### Critical Paths to Verify +### Critical Existing Features -These existing features MUST still work: - -#### Repository Operations -- [ ] Clone repository (HTTP and SSH) -- [ ] Push commits -- [ ] Create branches -- [ ] Create tags -- [ ] Pull requests work -- [ ] Merge operations work - -#### Wiki (V1 - Existing) -- [ ] Existing wiki pages load -- [ ] Create page via web UI -- [ ] Edit page via web UI -- [ ] Delete page via web UI -- [ ] V1 API endpoints still work: - - `GET /api/v1/repos/{owner}/{repo}/wiki/pages` - - `GET /api/v1/repos/{owner}/{repo}/wiki/page/{pageName}` - -#### Organizations -- [ ] Create organization -- [ ] Add/remove members -- [ ] Team management -- [ ] Repository creation in org - -#### User Operations -- [ ] Login/logout -- [ ] Profile settings -- [ ] SSH key management -- [ ] Access tokens - ---- - -## 5. Load Testing - -### Wiki Search Performance +These MUST still work: ```bash -# Install hey (HTTP load generator) -go install github.com/rakyll/hey@latest +# Repository clone +git clone http://localhost:3000/owner/repo.git -# Test search endpoint under load -hey -n 1000 -c 50 -H "Authorization: token $TOKEN" \ - "http://localhost:3000/api/v2/repos/test-org/test-repo/wiki/search?q=test" +# 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 ``` -### Expected Performance -- Search: < 500ms for wikis with < 100 pages -- List pages: < 200ms -- Get single page: < 100ms -- Graph generation: < 1s for wikis with < 100 pages +**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 --- -## 6. Database Migration Testing - -### Test Migration Rollback - -```bash -# Backup before testing -cp gitea.db gitea.db.backup - -# Run migrations -./gitea migrate - -# Verify tables created -sqlite3 gitea.db ".tables" | grep -E "(wiki_index|pages_|org_pinned)" - -# Check table structure -sqlite3 gitea.db ".schema wiki_index" -sqlite3 gitea.db ".schema pages_config" -sqlite3 gitea.db ".schema org_pinned_repo" -``` - -### Verify Data Integrity - -```sql --- Check no orphaned records -SELECT COUNT(*) FROM wiki_index WHERE repo_id NOT IN (SELECT id FROM repository); -SELECT COUNT(*) FROM pages_config WHERE repo_id NOT IN (SELECT id FROM repository); -SELECT COUNT(*) FROM org_pinned_repo WHERE org_id NOT IN (SELECT id FROM user WHERE type=1); -``` - ---- - -## 7. Staging Deployment - -### Recommended Staging Process - -1. **Clone Production Data** (sanitized) - ```bash - # Create sanitized copy of production DB - pg_dump production_db | psql staging_db - - # Remove sensitive data - UPDATE user SET passwd = 'disabled', salt = 'disabled' WHERE id > 1; - DELETE FROM access_token; - DELETE FROM oauth2_authorization_code; - ``` - -2. **Deploy to Staging** - ```bash - # Deploy v1.26.0 to staging - docker pull gitea/gitea:1.26.0 - docker-compose -f docker-compose.staging.yml up -d - ``` - -3. **Run Test Suite Against Staging** - ```bash - # Point tests at staging - export GITEA_URL=https://staging.gitea.example.com - export GITEA_TOKEN=staging-test-token - - # Run integration tests - go test -v ./tests/integration/... - ``` - -4. **Soak Test** (24-48 hours) - - Monitor error logs - - Check memory usage - - Verify no database locks - - Test with real (internal) users - ---- - -## 8. Rollback Plan - -### If Issues Found - -1. **Immediate Rollback** - ```bash - # Stop new version - docker-compose down - - # Restore previous version - docker pull gitea/gitea:1.25.3 - docker-compose up -d - ``` - -2. **Database Rollback** (if needed) - ```bash - # Restore from backup - pg_restore -d gitea gitea_backup.sql - - # Or for SQLite - cp gitea.db.backup gitea.db - ``` - -3. **New Tables Are Safe** - - Migration 326-328 only ADD tables - - No existing tables modified - - Rollback doesn't require table drops - - Old version simply ignores new tables - ---- - -## 9. Production Deployment Checklist - -### Pre-Deployment -- [ ] All automated tests passing -- [ ] Manual testing completed -- [ ] Staging deployment successful -- [ ] Database backup created -- [ ] Rollback procedure documented -- [ ] Maintenance window scheduled -- [ ] Users notified of downtime - -### Deployment -- [ ] Stop Gitea service -- [ ] Backup database -- [ ] Deploy new binary/container -- [ ] Run migrations -- [ ] Start Gitea service -- [ ] Verify health check endpoints -- [ ] Spot check critical features - -### Post-Deployment -- [ ] Monitor error logs for 1 hour -- [ ] Verify wiki search working -- [ ] Verify pages rendering -- [ ] Verify org profiles -- [ ] Check performance metrics -- [ ] Confirm with team leads - ---- - -## 10. Quick Smoke Test Script - -Save this as `smoke-test.sh`: +## 10. Complete Smoke Test Script ```bash #!/bin/bash set -e -BASE_URL="${GITEA_URL:-http://localhost:3000}" +BASE="${GITEA_URL:-http://localhost:3000}" TOKEN="${GITEA_TOKEN:-your-token}" -OWNER="test-org" -REPO="test-repo" +OWNER="${TEST_OWNER:-testorg}" +REPO="${TEST_REPO:-testrepo}" -echo "=== Gitea v1.26.0 Smoke Tests ===" +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' -# Health check -echo -n "Health check... " -curl -sf "$BASE_URL/api/v1/version" > /dev/null && echo "OK" || echo "FAIL" +pass() { echo -e "${GREEN}✓${NC} $1"; } +fail() { echo -e "${RED}✗${NC} $1"; FAILED=1; } -# Wiki V2 - List pages -echo -n "Wiki V2 - List pages... " -curl -sf -H "Authorization: token $TOKEN" \ - "$BASE_URL/api/v2/repos/$OWNER/$REPO/wiki/pages" > /dev/null && echo "OK" || echo "FAIL" +test_endpoint() { + local name=$1 + local method=${2:-GET} + local url=$3 + local data=$4 -# Wiki V2 - Search -echo -n "Wiki V2 - Search... " -curl -sf -H "Authorization: token $TOKEN" \ - "$BASE_URL/api/v2/repos/$OWNER/$REPO/wiki/search?q=test" > /dev/null && echo "OK" || echo "FAIL" + 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 +} -# Wiki V2 - Stats -echo -n "Wiki V2 - Stats... " -curl -sf -H "Authorization: token $TOKEN" \ - "$BASE_URL/api/v2/repos/$OWNER/$REPO/wiki/stats" > /dev/null && echo "OK" || echo "FAIL" +echo "=== Gitea v1.26.0 Comprehensive Smoke Tests ===" +echo "" -# Wiki V2 - Graph -echo -n "Wiki V2 - Graph... " -curl -sf -H "Authorization: token $TOKEN" \ - "$BASE_URL/api/v2/repos/$OWNER/$REPO/wiki/graph" > /dev/null && echo "OK" || echo "FAIL" +echo "--- Phase 1: API Reliability ---" +test_endpoint "Version endpoint" GET "$BASE/api/v1/version" +test_endpoint "Request ID header" GET "$BASE/api/v1/version" -# Org pinned repos -echo -n "Org pinned repos... " -curl -sf -H "Authorization: token $TOKEN" \ - "$BASE_URL/api/v1/orgs/$OWNER/pinned" > /dev/null && echo "OK" || echo "FAIL" +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\"}" -# Pages config -echo -n "Pages config... " -curl -sf -H "Authorization: token $TOKEN" \ - "$BASE_URL/api/v1/repos/$OWNER/$REPO/pages" > /dev/null && echo "OK" || echo "FAIL" +echo "" +echo "--- Phase 3: Reliability ---" +test_endpoint "Health Check" GET "$BASE/api/v2/health" -echo "=== Smoke Tests Complete ===" +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 ``` -Run with: +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 @@ -492,17 +969,41 @@ 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 -**Minimum Testing Before Production:** -1. Run automated test suite (`make test`) -2. Complete manual checklist for new features -3. Verify regression tests pass -4. Deploy to staging for 24+ hours -5. Run smoke tests after production deployment +**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 -**The new features are isolated:** -- V2 Wiki API is separate from V1 (won't break existing integrations) -- New database tables don't modify existing schema -- Pages feature is opt-in per repository -- Org pinned repos don't affect existing org functionality +**Recommended Testing Time:** +- Automated tests: 30 minutes +- Manual testing: 2-4 hours +- Staging soak test: 24-48 hours +- Total: 2-3 days before production