docs: add testing strategy and version requirements to schema plan
- Add PostgreSQL version requirements section (min 13, rec 15) - Add unit testing section for schema.go functions - Add concurrent startup manual test with 5 instances - Add debug hint in executeSchema error messages - Add PostgreSQL troubleshooting section - Update documentation requirements to include testing
This commit is contained in:
+107
-3
@@ -16,6 +16,17 @@
|
|||||||
|
|
||||||
## 📊 Technical Decisions
|
## 📊 Technical Decisions
|
||||||
|
|
||||||
|
### PostgreSQL Version Requirements
|
||||||
|
|
||||||
|
**Minimum: PostgreSQL 13** (for `gen_random_uuid()`)
|
||||||
|
**Recommended: PostgreSQL 15** (matches `docker-compose.yml`)
|
||||||
|
**IF NOT EXISTS syntax:** PostgreSQL 9.5+ (already satisfied by minimum version)
|
||||||
|
|
||||||
|
**Rationale:**
|
||||||
|
- PostgreSQL 13 introduced `gen_random_uuid()` as a built-in function
|
||||||
|
- PostgreSQL 15 is the current stable release and matches our deployment target
|
||||||
|
- All schema features (IF NOT EXISTS, CREATE OR REPLACE FUNCTION) work with PostgreSQL 9.5+
|
||||||
|
|
||||||
### 1. File Structure: Single Source of Truth
|
### 1. File Structure: Single Source of Truth
|
||||||
|
|
||||||
**Decision:** Single `internal/database/schema.go` file referencing existing `database/schema/schema.sql`.
|
**Decision:** Single `internal/database/schema.go` file referencing existing `database/schema/schema.sql`.
|
||||||
@@ -300,6 +311,7 @@ func executeSchema(ctx context.Context, db *pgxpool.Pool) error {
|
|||||||
|
|
||||||
_, err = tx.Exec(ctx, SchemaFile)
|
_, err = tx.Exec(ctx, SchemaFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Printf("HINT: Run manually to debug: psql -h localhost -U postgres -d bookhoard -f database/schema/schema.sql")
|
||||||
return fmt.Errorf("schema execution failed: %w", err)
|
return fmt.Errorf("schema execution failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,6 +426,53 @@ ls -la ../../database/schema/schema.sql
|
|||||||
# Should show the file exists at the correct relative location
|
# Should show the file exists at the correct relative location
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Step 2.3: Add Unit Tests for schema.go
|
||||||
|
|
||||||
|
Create `internal/database/schema_test.go`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParseTableNames(t *testing.T) {
|
||||||
|
tables, err := parseTableNames()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Greater(t, len(tables), 20, "Should parse at least 20 tables")
|
||||||
|
|
||||||
|
// Verify critical tables are detected
|
||||||
|
tableMap := make(map[string]bool)
|
||||||
|
for _, table := range tables {
|
||||||
|
tableMap[table] = true
|
||||||
|
}
|
||||||
|
assert.True(t, tableMap["users"], "Should find 'users' table")
|
||||||
|
assert.True(t, tableMap["libraries"], "Should find 'libraries' table")
|
||||||
|
assert.True(t, tableMap["media_items"], "Should find 'media_items' table")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateLockID(t *testing.T) {
|
||||||
|
result := generateLockID("bookhoard:schema:init")
|
||||||
|
assert.Equal(t, int64(7804706162000639061), result, "FNV-1a hash must match expected value")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVerifyTables_MissingTables(t *testing.T) {
|
||||||
|
// This would require a mock database or test setup
|
||||||
|
// For now, skip or implement with pgxpool mock
|
||||||
|
t.Skip("Requires database connection - implement in integration tests")
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Run tests with:
|
||||||
|
```bash
|
||||||
|
go test ./internal/database -v
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Phase 3: Integrate into main.go
|
### Phase 3: Integrate into main.go
|
||||||
@@ -481,6 +540,7 @@ func main() {
|
|||||||
- [ ] No schema file duplication (single source of truth)
|
- [ ] No schema file duplication (single source of truth)
|
||||||
- [ ] Verifies critical functions exist, not just tables
|
- [ ] Verifies critical functions exist, not just tables
|
||||||
- [ ] Provides clear error messages for missing schema components
|
- [ ] Provides clear error messages for missing schema components
|
||||||
|
- [ ] Includes debug hint when schema execution fails (psql command)
|
||||||
|
|
||||||
**Phase 3 Verification:**
|
**Phase 3 Verification:**
|
||||||
- [ ] `cmd/server/main.go` compiles without errors
|
- [ ] `cmd/server/main.go` compiles without errors
|
||||||
@@ -491,7 +551,7 @@ func main() {
|
|||||||
**Integration Testing:**
|
**Integration Testing:**
|
||||||
- [ ] Fresh database initializes correctly
|
- [ ] Fresh database initializes correctly
|
||||||
- [ ] Existing database doesn't break
|
- [ ] Existing database doesn't break
|
||||||
- [ ] Concurrent startup works with advisory locks
|
- [ ] Concurrent startup works with advisory locks (manual test below)
|
||||||
- [ ] Partial state recovers successfully
|
- [ ] Partial state recovers successfully
|
||||||
- [ ] TestKoboInitialization passes
|
- [ ] TestKoboInitialization passes
|
||||||
- [ ] All integration tests pass
|
- [ ] All integration tests pass
|
||||||
@@ -502,6 +562,32 @@ func main() {
|
|||||||
- [ ] `go build ./...` succeeds for entire project
|
- [ ] `go build ./...` succeeds for entire project
|
||||||
- [ ] `bash scripts/verify-guidelines.sh` passes (0 errors)
|
- [ ] `bash scripts/verify-guidelines.sh` passes (0 errors)
|
||||||
|
|
||||||
|
**Concurrent Startup Test (Manual):**
|
||||||
|
```bash
|
||||||
|
# Test advisory locks work correctly with multiple instances
|
||||||
|
# Start 5 instances simultaneously
|
||||||
|
for i in {1..5}; do
|
||||||
|
podman compose -p test$i up -d app
|
||||||
|
sleep 0.5 # Stagger starts slightly
|
||||||
|
done
|
||||||
|
|
||||||
|
# Wait 10 seconds for all to initialize
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# Check all logs for successful initialization
|
||||||
|
for i in {1..5}; do
|
||||||
|
echo "=== Instance $i ==="
|
||||||
|
podman logs test$i_bookhoard_app 2>&1 | grep "schema initialization complete"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
for i in {1..5}; do
|
||||||
|
podman compose -p test$i down
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected result:** All 5 instances should show "schema initialization complete" in logs, proving advisory locks prevent race conditions.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📈 Expected Outcomes
|
## 📈 Expected Outcomes
|
||||||
@@ -585,6 +671,23 @@ If new version has schema issues:
|
|||||||
|
|
||||||
## 📞 Support
|
## 📞 Support
|
||||||
|
|
||||||
|
### PostgreSQL Version Issues
|
||||||
|
|
||||||
|
If you see errors about `gen_random_uuid()` not existing:
|
||||||
|
```bash
|
||||||
|
# Check PostgreSQL version
|
||||||
|
podman exec bookhoard_db psql --version
|
||||||
|
# Should be 13.0 or higher
|
||||||
|
```
|
||||||
|
|
||||||
|
If using an older PostgreSQL version, update `docker-compose.yml`:
|
||||||
|
```yaml
|
||||||
|
db:
|
||||||
|
image: postgres:15-alpine # Or postgres:13-alpine minimum
|
||||||
|
```
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
If issues occur:
|
If issues occur:
|
||||||
|
|
||||||
### Check logs first:
|
### Check logs first:
|
||||||
@@ -623,8 +726,9 @@ podman compose up -d
|
|||||||
## 📚 Documentation
|
## 📚 Documentation
|
||||||
|
|
||||||
Create documentation explaining the automatic schema initialization:
|
Create documentation explaining the automatic schema initialization:
|
||||||
- **docs/contributing/database-schema.md** - How schema initialization works, how to modify schema safely
|
- **docs/contributing/database-schema.md** - How schema initialization works, how to modify schema safely, PostgreSQL version requirements
|
||||||
- **README.md** - Add "Database Initialization" section documenting first-run behavior
|
- **README.md** - Add "Database Initialization" section documenting first-run behavior and PostgreSQL version requirements
|
||||||
|
- **internal/database/schema_test.go** - Unit tests for schema parsing and verification functions
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user