# 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: <short-uuid>

# 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: <configured limit>
# X-RateLimit-Remaining: <remaining>
# X-RateLimit-Reset: <unix timestamp>
```

**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 <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
