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
|
||||
|
||||
### 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
|
||||
|
||||
**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)
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -414,6 +426,53 @@ ls -la ../../database/schema/schema.sql
|
||||
# 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
|
||||
@@ -481,6 +540,7 @@ func main() {
|
||||
- [ ] No schema file duplication (single source of truth)
|
||||
- [ ] Verifies critical functions exist, not just tables
|
||||
- [ ] Provides clear error messages for missing schema components
|
||||
- [ ] Includes debug hint when schema execution fails (psql command)
|
||||
|
||||
**Phase 3 Verification:**
|
||||
- [ ] `cmd/server/main.go` compiles without errors
|
||||
@@ -491,7 +551,7 @@ func main() {
|
||||
**Integration Testing:**
|
||||
- [ ] Fresh database initializes correctly
|
||||
- [ ] Existing database doesn't break
|
||||
- [ ] Concurrent startup works with advisory locks
|
||||
- [ ] Concurrent startup works with advisory locks (manual test below)
|
||||
- [ ] Partial state recovers successfully
|
||||
- [ ] TestKoboInitialization passes
|
||||
- [ ] All integration tests pass
|
||||
@@ -502,6 +562,32 @@ func main() {
|
||||
- [ ] `go build ./...` succeeds for entire project
|
||||
- [ ] `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
|
||||
@@ -585,6 +671,23 @@ If new version has schema issues:
|
||||
|
||||
## 📞 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:
|
||||
|
||||
### Check logs first:
|
||||
@@ -623,8 +726,9 @@ podman compose up -d
|
||||
## 📚 Documentation
|
||||
|
||||
Create documentation explaining the automatic schema initialization:
|
||||
- **docs/contributing/database-schema.md** - How schema initialization works, how to modify schema safely
|
||||
- **README.md** - Add "Database Initialization" section documenting first-run behavior
|
||||
- **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 and PostgreSQL version requirements
|
||||
- **internal/database/schema_test.go** - Unit tests for schema parsing and verification functions
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user