summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-14 11:22:02 +0300
committerPaul Buetow <paul@buetow.org>2026-04-14 11:22:02 +0300
commitc19666bd44b938ab2627b0c85935d3877c88b373 (patch)
tree434e7d2942cd79428106c2f8ede74d8309f1a6d3 /internal
parent55593e14ee2a4225d1db1058da9d8d1f663225b6 (diff)
refactor: drop goprecords DB pass-through, use storage from CLI (x3)
Remove OpenDB/CreateSchema/ResetRecords/ImportFromDir/ImportFromFS wrappers and sqlite blank import from goprecords; keep LoadAggregates. CLI and integration tests call storage.* directly. Storage-focused tests live under internal/storage. Made-with: Cursor
Diffstat (limited to 'internal')
-rw-r--r--internal/cli/cli.go9
-rw-r--r--internal/goprecords/db.go29
-rw-r--r--internal/goprecords/db_test.go201
-rw-r--r--internal/goprecords/integration_test_runner.go8
-rw-r--r--internal/goprecords/integration_test_runner_test.go4
-rw-r--r--internal/storage/db_test.go169
6 files changed, 192 insertions, 228 deletions
diff --git a/internal/cli/cli.go b/internal/cli/cli.go
index 7dd7cb6..81ebc40 100644
--- a/internal/cli/cli.go
+++ b/internal/cli/cli.go
@@ -12,6 +12,7 @@ import (
"codeberg.org/snonux/goprecords/internal/authkeys"
"codeberg.org/snonux/goprecords/internal/daemon"
"codeberg.org/snonux/goprecords/internal/goprecords"
+ "codeberg.org/snonux/goprecords/internal/storage"
"codeberg.org/snonux/goprecords/internal/version"
)
@@ -62,15 +63,15 @@ func runImport(args []string) error {
return fmt.Errorf("missing -stats-dir")
}
ctx := context.Background()
- db, err := goprecords.OpenDB(ctx, *dbPath)
+ db, err := storage.Open(ctx, *dbPath)
if err != nil {
return fmt.Errorf("open db: %w", err)
}
defer db.Close()
- if err := goprecords.CreateSchema(ctx, db); err != nil {
+ if err := storage.CreateSchema(ctx, db); err != nil {
return fmt.Errorf("schema: %w", err)
}
- if err := goprecords.ImportFromDir(ctx, db, *statsDir); err != nil {
+ if err := storage.ImportFromDir(ctx, db, *statsDir); err != nil {
return fmt.Errorf("import: %w", err)
}
fmt.Fprintf(os.Stderr, "imported %s into %s\n", *statsDir, *dbPath)
@@ -85,7 +86,7 @@ func runQuery(args []string) error {
return err
}
ctx := context.Background()
- db, err := goprecords.OpenDB(ctx, *dbPath)
+ db, err := storage.Open(ctx, *dbPath)
if err != nil {
return fmt.Errorf("open db: %w", err)
}
diff --git a/internal/goprecords/db.go b/internal/goprecords/db.go
index 2bcfb78..b2b095b 100644
--- a/internal/goprecords/db.go
+++ b/internal/goprecords/db.go
@@ -4,39 +4,10 @@ import (
"context"
"database/sql"
"fmt"
- "io/fs"
"codeberg.org/snonux/goprecords/internal/storage"
- _ "modernc.org/sqlite"
)
-// OpenDB opens the SQLite database at path, creating the file if needed.
-func OpenDB(ctx context.Context, path string) (*sql.DB, error) {
- return storage.Open(ctx, path)
-}
-
-// CreateSchema creates the record table and indexes (idempotent).
-func CreateSchema(ctx context.Context, db *sql.DB) error {
- return storage.CreateSchema(ctx, db)
-}
-
-// ResetRecords removes all rows so import is repeatable.
-func ResetRecords(ctx context.Context, db *sql.DB) error {
- return storage.ResetRecords(ctx, db)
-}
-
-// ImportFromDir reads all .records files from statsDir and inserts into the DB.
-// Resets the record table first so the run is repeatable.
-func ImportFromDir(ctx context.Context, db *sql.DB, statsDir string) error {
- return storage.ImportFromDir(ctx, db, statsDir)
-}
-
-// ImportFromFS reads all non-empty .records files from the root of fsys and inserts into the DB.
-// Resets the record table first so the run is repeatable.
-func ImportFromFS(ctx context.Context, db *sql.DB, fsys fs.FS) error {
- return storage.ImportFromFS(ctx, db, fsys)
-}
-
// LoadAggregates reads all rows from the DB and builds Aggregates (same shape as file-based aggregation).
func LoadAggregates(ctx context.Context, db *sql.DB) (*Aggregates, error) {
records, err := storage.LoadRecords(ctx, db)
diff --git a/internal/goprecords/db_test.go b/internal/goprecords/db_test.go
index 0edbae9..3d6b788 100644
--- a/internal/goprecords/db_test.go
+++ b/internal/goprecords/db_test.go
@@ -3,207 +3,28 @@ package goprecords
import (
"context"
"math"
- "os"
"path/filepath"
"strings"
"testing"
- "testing/fstest"
-)
-
-func TestOpenDB(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- db, err := OpenDB(context.Background(), dbPath)
- if err != nil {
- t.Fatalf("failed to open DB: %v", err)
- }
- defer db.Close()
-
- if db == nil {
- t.Error("expected non-nil database")
- }
-}
-
-func TestCreateSchema(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- db, err := OpenDB(context.Background(), dbPath)
- if err != nil {
- t.Fatalf("failed to open DB: %v", err)
- }
- defer db.Close()
-
- ctx := context.Background()
- err = CreateSchema(ctx, db)
- if err != nil {
- t.Fatalf("failed to create schema: %v", err)
- }
- // Verify schema was created by checking if we can query it
- _, err = db.ExecContext(ctx, "SELECT 1 FROM record LIMIT 1")
- if err != nil {
- t.Fatalf("failed to query record table: %v", err)
- }
-}
-
-func TestResetRecords(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- db, err := OpenDB(context.Background(), dbPath)
- if err != nil {
- t.Fatalf("failed to open DB: %v", err)
- }
- defer db.Close()
-
- ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
- t.Fatalf("failed to create schema: %v", err)
- }
-
- // Insert a record
- _, err = db.ExecContext(ctx,
- "INSERT INTO record (host, uptime_sec, boot_time, os, os_kernel_name, os_kernel_major) VALUES (?, ?, ?, ?, ?, ?)",
- "host1", 1000, 2000, "Linux 5.10", "Linux", "Linux 5...")
- if err != nil {
- t.Fatalf("failed to insert record: %v", err)
- }
-
- // Reset records
- err = ResetRecords(ctx, db)
- if err != nil {
- t.Fatalf("failed to reset records: %v", err)
- }
-
- // Verify records are empty
- var count int
- err = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&count)
- if err != nil {
- t.Fatalf("failed to count records: %v", err)
- }
-
- if count != 0 {
- t.Errorf("expected 0 records after reset, got %d", count)
- }
-}
-
-func TestImportFromDir(t *testing.T) {
- // Create temp directory with test records
- tmpDir := t.TempDir()
-
- // Create a test records file
- recordsFile := filepath.Join(tmpDir, "testhost.records")
- content := []byte("86400:1000000:Linux 5.10.0-test\n" +
- "86400:1000001:Linux 5.10.0-test\n" +
- "86400:1000002:Linux 5.10.0-test\n")
-
- if err := os.WriteFile(recordsFile, content, 0644); err != nil {
- t.Fatalf("failed to create test file: %v", err)
- }
-
- // Create database
- dbPath := filepath.Join(tmpDir, "test.db")
- db, err := OpenDB(context.Background(), dbPath)
- if err != nil {
- t.Fatalf("failed to open DB: %v", err)
- }
- defer db.Close()
-
- ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
- t.Fatalf("failed to create schema: %v", err)
- }
-
- // Import records
- err = ImportFromDir(ctx, db, tmpDir)
- if err != nil {
- t.Fatalf("failed to import records: %v", err)
- }
-
- // Verify records were imported
- var count int
- err = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&count)
- if err != nil {
- t.Fatalf("failed to count records: %v", err)
- }
-
- if count != 3 {
- t.Errorf("expected 3 records after import, got %d", count)
- }
-}
-
-func TestImportFromFS_MapFS(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
- db, err := OpenDB(context.Background(), dbPath)
- if err != nil {
- t.Fatalf("open DB: %v", err)
- }
- defer db.Close()
- ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
- t.Fatalf("schema: %v", err)
- }
- m := fstest.MapFS{
- "testhost.records": &fstest.MapFile{
- Data: []byte("86400:1000000:Linux 5.10.0-test\n" +
- "86400:1000001:Linux 5.10.0-test\n" +
- "86400:1000002:Linux 5.10.0-test\n"),
- Mode: 0o644,
- },
- }
- if err := ImportFromFS(ctx, db, m); err != nil {
- t.Fatalf("ImportFromFS: %v", err)
- }
- var count int
- if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&count); err != nil {
- t.Fatal(err)
- }
- if count != 3 {
- t.Errorf("count = %d, want 3", count)
- }
-}
-
-func TestImportFromDirInvalidPath(t *testing.T) {
- tmpDir := t.TempDir()
- dbPath := filepath.Join(tmpDir, "test.db")
-
- db, err := OpenDB(context.Background(), dbPath)
- if err != nil {
- t.Fatalf("failed to open DB: %v", err)
- }
- defer db.Close()
-
- ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
- t.Fatalf("failed to create schema: %v", err)
- }
-
- // Try to import from non-existent directory
- err = ImportFromDir(ctx, db, "/nonexistent/path")
- if err == nil {
- t.Error("expected error for non-existent directory")
- }
-}
+ "codeberg.org/snonux/goprecords/internal/storage"
+)
func TestLoadAggregates(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "test.db")
- db, err := OpenDB(context.Background(), dbPath)
+ db, err := storage.Open(context.Background(), dbPath)
if err != nil {
t.Fatalf("failed to open DB: %v", err)
}
defer db.Close()
ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
+ if err := storage.CreateSchema(ctx, db); err != nil {
t.Fatalf("failed to create schema: %v", err)
}
- // Insert some records
_, err = db.ExecContext(ctx,
"INSERT INTO record (host, uptime_sec, boot_time, os, os_kernel_name, os_kernel_major) VALUES (?, ?, ?, ?, ?, ?)",
"host1", 1000, 2000, "Linux 5.10", "Linux", "Linux 5...")
@@ -218,7 +39,6 @@ func TestLoadAggregates(t *testing.T) {
t.Fatalf("failed to insert: %v", err)
}
- // Load aggregates
aggs, err := LoadAggregates(ctx, db)
if err != nil {
t.Fatalf("failed to load aggregates: %v", err)
@@ -249,14 +69,14 @@ func TestLoadAggregatesLastKernelMaxBootNearInt64(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "test.db")
- db, err := OpenDB(context.Background(), dbPath)
+ db, err := storage.Open(context.Background(), dbPath)
if err != nil {
t.Fatalf("failed to open DB: %v", err)
}
defer db.Close()
ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
+ if err := storage.CreateSchema(ctx, db); err != nil {
t.Fatalf("failed to create schema: %v", err)
}
@@ -295,18 +115,17 @@ func TestLoadAggregatesEmptyDB(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "test.db")
- db, err := OpenDB(context.Background(), dbPath)
+ db, err := storage.Open(context.Background(), dbPath)
if err != nil {
t.Fatalf("failed to open DB: %v", err)
}
defer db.Close()
ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
+ if err := storage.CreateSchema(ctx, db); err != nil {
t.Fatalf("failed to create schema: %v", err)
}
- // Load from empty database
aggs, err := LoadAggregates(ctx, db)
if err != nil {
t.Fatalf("failed to load aggregates: %v", err)
@@ -325,13 +144,13 @@ func TestLoadAggregatesWrapsLoadRecordsError(t *testing.T) {
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "test.db")
- db, err := OpenDB(context.Background(), dbPath)
+ db, err := storage.Open(context.Background(), dbPath)
if err != nil {
t.Fatalf("failed to open DB: %v", err)
}
ctx := context.Background()
- if err := CreateSchema(ctx, db); err != nil {
+ if err := storage.CreateSchema(ctx, db); err != nil {
db.Close()
t.Fatalf("failed to create schema: %v", err)
}
diff --git a/internal/goprecords/integration_test_runner.go b/internal/goprecords/integration_test_runner.go
index 0d07276..448dcd7 100644
--- a/internal/goprecords/integration_test_runner.go
+++ b/internal/goprecords/integration_test_runner.go
@@ -5,6 +5,8 @@ import (
"database/sql"
"fmt"
"os"
+
+ "codeberg.org/snonux/goprecords/internal/storage"
)
// RunIntegrationTests runs integration tests against fixture data.
@@ -94,7 +96,7 @@ func testImportExport(ctx context.Context, aggregates *Aggregates, fixturesDir s
_ = os.Remove(tmpDB)
return 1
}
- db, err := OpenDB(ctx, tmpDB)
+ db, err := storage.Open(ctx, tmpDB)
if err != nil {
_ = os.Remove(tmpDB)
fmt.Printf("FAIL: open tmp db: %v\n", err)
@@ -108,12 +110,12 @@ func testImportExportOnDB(ctx context.Context, db *sql.DB, tmpDB string, aggrega
db.Close()
_ = os.Remove(tmpDB)
}()
- if err := CreateSchema(ctx, db); err != nil {
+ if err := storage.CreateSchema(ctx, db); err != nil {
fmt.Printf("FAIL: create schema: %v\n", err)
return 1
}
failed := 0
- if err := ImportFromDir(ctx, db, fixturesDir); err != nil {
+ if err := storage.ImportFromDir(ctx, db, fixturesDir); err != nil {
fmt.Printf("FAIL: import: %v\n", err)
return 1
}
diff --git a/internal/goprecords/integration_test_runner_test.go b/internal/goprecords/integration_test_runner_test.go
index 29de945..20476b7 100644
--- a/internal/goprecords/integration_test_runner_test.go
+++ b/internal/goprecords/integration_test_runner_test.go
@@ -4,6 +4,8 @@ import (
"context"
"path/filepath"
"testing"
+
+ "codeberg.org/snonux/goprecords/internal/storage"
)
func TestTestImportExportOnDB_createSchemaError(t *testing.T) {
@@ -16,7 +18,7 @@ func TestTestImportExportOnDB_createSchemaError(t *testing.T) {
}
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "import.db")
- db, err := OpenDB(ctx, dbPath)
+ db, err := storage.Open(ctx, dbPath)
if err != nil {
t.Fatal(err)
}
diff --git a/internal/storage/db_test.go b/internal/storage/db_test.go
index 5415235..b05b4c7 100644
--- a/internal/storage/db_test.go
+++ b/internal/storage/db_test.go
@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"testing"
+ "testing/fstest"
)
func TestOpen_ContextCanceled(t *testing.T) {
@@ -32,3 +33,171 @@ func TestOpen_PingFailsOnDirectoryPath(t *testing.T) {
t.Fatal("expected error opening sqlite at directory path")
}
}
+
+func TestOpen_createsDatabaseFile(t *testing.T) {
+ tmpDir := t.TempDir()
+ dbPath := filepath.Join(tmpDir, "test.db")
+
+ db, err := Open(context.Background(), dbPath)
+ if err != nil {
+ t.Fatalf("failed to open DB: %v", err)
+ }
+ defer db.Close()
+
+ if db == nil {
+ t.Error("expected non-nil database")
+ }
+}
+
+func TestCreateSchema(t *testing.T) {
+ tmpDir := t.TempDir()
+ dbPath := filepath.Join(tmpDir, "test.db")
+
+ db, err := Open(context.Background(), dbPath)
+ if err != nil {
+ t.Fatalf("failed to open DB: %v", err)
+ }
+ defer db.Close()
+
+ ctx := context.Background()
+ err = CreateSchema(ctx, db)
+ if err != nil {
+ t.Fatalf("failed to create schema: %v", err)
+ }
+
+ _, err = db.ExecContext(ctx, "SELECT 1 FROM record LIMIT 1")
+ if err != nil {
+ t.Fatalf("failed to query record table: %v", err)
+ }
+}
+
+func TestResetRecords(t *testing.T) {
+ tmpDir := t.TempDir()
+ dbPath := filepath.Join(tmpDir, "test.db")
+
+ db, err := Open(context.Background(), dbPath)
+ if err != nil {
+ t.Fatalf("failed to open DB: %v", err)
+ }
+ defer db.Close()
+
+ ctx := context.Background()
+ if err := CreateSchema(ctx, db); err != nil {
+ t.Fatalf("failed to create schema: %v", err)
+ }
+
+ _, err = db.ExecContext(ctx,
+ "INSERT INTO record (host, uptime_sec, boot_time, os, os_kernel_name, os_kernel_major) VALUES (?, ?, ?, ?, ?, ?)",
+ "host1", 1000, 2000, "Linux 5.10", "Linux", "Linux 5...")
+ if err != nil {
+ t.Fatalf("failed to insert record: %v", err)
+ }
+
+ err = ResetRecords(ctx, db)
+ if err != nil {
+ t.Fatalf("failed to reset records: %v", err)
+ }
+
+ var count int
+ err = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&count)
+ if err != nil {
+ t.Fatalf("failed to count records: %v", err)
+ }
+
+ if count != 0 {
+ t.Errorf("expected 0 records after reset, got %d", count)
+ }
+}
+
+func TestImportFromDir(t *testing.T) {
+ tmpDir := t.TempDir()
+
+ recordsFile := filepath.Join(tmpDir, "testhost.records")
+ content := []byte("86400:1000000:Linux 5.10.0-test\n" +
+ "86400:1000001:Linux 5.10.0-test\n" +
+ "86400:1000002:Linux 5.10.0-test\n")
+
+ if err := os.WriteFile(recordsFile, content, 0644); err != nil {
+ t.Fatalf("failed to create test file: %v", err)
+ }
+
+ dbPath := filepath.Join(tmpDir, "test.db")
+ db, err := Open(context.Background(), dbPath)
+ if err != nil {
+ t.Fatalf("failed to open DB: %v", err)
+ }
+ defer db.Close()
+
+ ctx := context.Background()
+ if err := CreateSchema(ctx, db); err != nil {
+ t.Fatalf("failed to create schema: %v", err)
+ }
+
+ err = ImportFromDir(ctx, db, tmpDir)
+ if err != nil {
+ t.Fatalf("failed to import records: %v", err)
+ }
+
+ var count int
+ err = db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&count)
+ if err != nil {
+ t.Fatalf("failed to count records: %v", err)
+ }
+
+ if count != 3 {
+ t.Errorf("expected 3 records after import, got %d", count)
+ }
+}
+
+func TestImportFromFS_MapFS(t *testing.T) {
+ tmpDir := t.TempDir()
+ dbPath := filepath.Join(tmpDir, "test.db")
+ db, err := Open(context.Background(), dbPath)
+ if err != nil {
+ t.Fatalf("open DB: %v", err)
+ }
+ defer db.Close()
+ ctx := context.Background()
+ if err := CreateSchema(ctx, db); err != nil {
+ t.Fatalf("schema: %v", err)
+ }
+ m := fstest.MapFS{
+ "testhost.records": &fstest.MapFile{
+ Data: []byte("86400:1000000:Linux 5.10.0-test\n" +
+ "86400:1000001:Linux 5.10.0-test\n" +
+ "86400:1000002:Linux 5.10.0-test\n"),
+ Mode: 0o644,
+ },
+ }
+ if err := ImportFromFS(ctx, db, m); err != nil {
+ t.Fatalf("ImportFromFS: %v", err)
+ }
+ var count int
+ if err := db.QueryRowContext(ctx, "SELECT COUNT(*) FROM record").Scan(&count); err != nil {
+ t.Fatal(err)
+ }
+ if count != 3 {
+ t.Errorf("count = %d, want 3", count)
+ }
+}
+
+func TestImportFromDir_invalidPath(t *testing.T) {
+ tmpDir := t.TempDir()
+ dbPath := filepath.Join(tmpDir, "test.db")
+
+ db, err := Open(context.Background(), dbPath)
+ if err != nil {
+ t.Fatalf("failed to open DB: %v", err)
+ }
+ defer db.Close()
+
+ ctx := context.Background()
+ if err := CreateSchema(ctx, db); err != nil {
+ t.Fatalf("failed to create schema: %v", err)
+ }
+
+ err = ImportFromDir(ctx, db, "/nonexistent/path")
+ if err == nil {
+ t.Error("expected error for non-existent directory")
+ }
+}