- Create modular architecture with separate packages for config, database, HTTP, logging, and state management - Implement Cobra CLI with daemon command - Set up Uber FX dependency injection - Add Chi router with health check and IP lookup endpoints - Implement GeoIP database downloader with automatic updates - Add state persistence for tracking database download times - Include comprehensive test coverage for all components - Configure structured logging with slog - Add Makefile with test, lint, and build targets - Support both IPv4 and IPv6 lookups - Return country, city, ASN, and location data in JSON format
88 lines
1.7 KiB
Go
88 lines
1.7 KiB
Go
package database
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.eeqj.de/sneak/ipapi/internal/config"
|
|
"git.eeqj.de/sneak/ipapi/internal/state"
|
|
)
|
|
|
|
func TestNeedsUpdate(t *testing.T) {
|
|
tmpFile, err := os.CreateTemp("", "test-db")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.Remove(tmpFile.Name())
|
|
tmpFile.Close()
|
|
|
|
tests := []struct {
|
|
name string
|
|
filePath string
|
|
lastDownload time.Time
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "file doesn't exist",
|
|
filePath: "/nonexistent/file",
|
|
lastDownload: time.Now(),
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "recent download",
|
|
filePath: tmpFile.Name(),
|
|
lastDownload: time.Now().Add(-time.Hour),
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "old download",
|
|
filePath: tmpFile.Name(),
|
|
lastDownload: time.Now().Add(-8 * 24 * time.Hour),
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := needsUpdate(tt.filePath, tt.lastDownload)
|
|
if result != tt.expected {
|
|
t.Errorf("expected %v, got %v", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
tmpDir, err := os.MkdirTemp("", "ipapi-db-test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
cfg := &config.Config{
|
|
StateDir: tmpDir,
|
|
}
|
|
logger := slog.Default()
|
|
stateManager, err := state.New(cfg, logger)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
manager, err := New(cfg, logger, stateManager)
|
|
if err != nil {
|
|
t.Fatalf("failed to create database manager: %v", err)
|
|
}
|
|
|
|
if manager == nil {
|
|
t.Fatal("expected manager, got nil")
|
|
}
|
|
|
|
expectedDataDir := filepath.Join(tmpDir, "databases")
|
|
if manager.dataDir != expectedDataDir {
|
|
t.Errorf("expected data dir %s, got %s", expectedDataDir, manager.dataDir)
|
|
}
|
|
}
|