Files
openfsd/db/config_sqlite_test.go
Reese Norris 335409c4b4 Add ConfigRepository and enhance server configuration management
1. Database Enhancements (db/repositories.go):
   - Added ConfigRepository interface and implementations for PostgreSQL and SQLite
   - Updated Repositories struct to include ConfigRepository
   - Modified NewRepositories to initialize both UserRepo and ConfigRepo

2. FSD Server Improvements:
   - Removed hardcoded jwtSecret, now retrieved from ConfigRepository (fsd/conn.go, web/auth.go)
   - Added dynamic welcome message retrieval from ConfigRepository (fsd/conn.go)
   - Optimized METAR buffer size from 4096 to 512 bytes (fsd/metar.go)
   - Reduced minimum fields for DeleteATC and DeletePilot packets (fsd/packet.go)
   - Improved Haversine distance calculation with constants (fsd/postoffice.go)
   - Added thread-safety documentation for sendError (fsd/client.go)

3. Server Configuration (fsd/server.go):
   - Added NewDefaultServer to initialize server with environment-based config
   - Implemented automatic database migration and default admin user creation
   - Added configurable METAR worker count
   - Improved logging with slog and environment-based debug level

4. Web Interface Enhancements:
   - Added user and config editor frontend routes (web/frontend.go, web/routes.go)
   - Improved JWT handling by retrieving secret from ConfigRepository (web/auth.go)
   - Enhanced user management API endpoints (web/user.go)
   - Updated dashboard to display CID and conditional admin links (web/templates/dashboard.html)
   - Embedded templates using go:embed (web/templates.go)

5. Frontend JavaScript Improvements:
   - Added networkRatingFromInt helper for readable ratings (web/static/js/openfsd/dashboard.js)
   - Improved API request handling with auth/no-auth variants (web/static/js/openfsd/api.js)

6. Miscellaneous:
   - Added sethvargo/go-envconfig dependency for environment variable parsing
   - Fixed parseVisRange to use 64-bit float parsing (fsd/util.go)
   - Added strPtr utility function (fsd/util.go, web/main.go)
   - Improved SVG logo rendering in layout (web/templates/layout.html)
2025-05-16 22:27:26 -07:00

177 lines
4.4 KiB
Go

package db
import (
"database/sql"
"errors"
_ "modernc.org/sqlite"
"testing"
)
// setupConfigTestDB initializes an in-memory SQLite database, applies migrations, and returns the database connection and repository.
func setupConfigTestDB(t *testing.T) (*sql.DB, *SQLiteConfigRepository) {
db, err := sql.Open("sqlite", ":memory:")
if err != nil {
t.Fatalf("failed to open database: %v", err)
}
err = Migrate(db)
if err != nil {
t.Fatalf("failed to migrate database: %v", err)
}
repo := &SQLiteConfigRepository{db: db}
return db, repo
}
// TestInitDefault verifies that InitDefault correctly inserts the JWT secret key and does not overwrite it on subsequent calls.
func TestInitDefault(t *testing.T) {
db, repo := setupConfigTestDB(t)
defer db.Close()
// Initially, the key should not exist
_, err := repo.Get(ConfigJwtSecretKey)
if !errors.Is(err, ErrConfigKeyNotFound) {
t.Errorf("expected ErrConfigKeyNotFound, got %v", err)
}
// Call InitDefault
err = repo.InitDefault()
if err != nil {
t.Errorf("expected no error, got %v", err)
}
// Verify the key exists and is a 32-character hex string
value, err := repo.Get(ConfigJwtSecretKey)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if len(value) != 32 {
t.Errorf("expected 32-character hex string, got %s", value)
}
// Call InitDefault again
err = repo.InitDefault()
if err != nil {
t.Errorf("expected no error, got %v", err)
}
// Verify the key has not changed
newValue, err := repo.Get(ConfigJwtSecretKey)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if newValue != value {
t.Errorf("expected the same value, but it changed from %s to %s", value, newValue)
}
}
// TestSet verifies that Set correctly inserts new key-value pairs and updates existing ones.
func TestSet(t *testing.T) {
db, repo := setupConfigTestDB(t)
defer db.Close()
// Set a new key-value pair
key := "test_key"
value := "test_value"
err := repo.Set(key, value)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
// Retrieve and verify
retrievedValue, err := repo.Get(key)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if retrievedValue != value {
t.Errorf("expected %s, got %s", value, retrievedValue)
}
// Update the key with a new value
newValue := "new_test_value"
err = repo.Set(key, newValue)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
// Retrieve and verify again
retrievedValue, err = repo.Get(key)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if retrievedValue != newValue {
t.Errorf("expected %s, got %s", newValue, retrievedValue)
}
}
// TestGet verifies that Get retrieves values for existing keys and returns an error for non-existing keys.
func TestGet(t *testing.T) {
db, repo := setupConfigTestDB(t)
defer db.Close()
// Try to get a non-existing key
_, err := repo.Get("non_existing_key")
if !errors.Is(err, ErrConfigKeyNotFound) {
t.Errorf("expected ErrConfigKeyNotFound, got %v", err)
}
// Set a key-value pair
key := "another_key"
value := "another_value"
err = repo.Set(key, value)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
// Retrieve and verify
retrievedValue, err := repo.Get(key)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if retrievedValue != value {
t.Errorf("expected %s, got %s", value, retrievedValue)
}
}
// TestMultipleSets verifies that setting multiple keys works correctly and updating one does not affect others.
func TestMultipleSets(t *testing.T) {
db, repo := setupConfigTestDB(t)
defer db.Close()
// Set multiple keys
err := repo.Set("key1", "value1")
if err != nil {
t.Errorf("expected no error, got %v", err)
}
err = repo.Set("key2", "value2")
if err != nil {
t.Errorf("expected no{kcal error, got %v", err)
}
// Retrieve and verify
val1, err := repo.Get("key1")
if err != nil || val1 != "value1" {
t.Errorf("expected value1, got %s, err %v", val1, err)
}
val2, err := repo.Get("key2")
if err != nil || val2 != "value2" {
t.Errorf("expected value2, got %s, err %v", val2, err)
}
// Update one key
err = repo.Set("key1", "new_value1")
if err != nil {
t.Errorf("expected no error, got %v", err)
}
// Check both keys
val1, err = repo.Get("key1")
if err != nil || val1 != "new_value1" {
t.Errorf("expected new_value1, got %s, err %v", val1, err)
}
val2, err = repo.Get("key2")
if err != nil || val2 != "value2" {
t.Errorf("expected value2, got %s, err %v", val2, err)
}
}