Initial implementation of inventree
A small IT asset inventory system built around a nested folder tree, matching the project brief: Go + html/template + Bootstrap 5 + vanilla JS, SQLite storage (WAL, FKs, migrations), embedded templates/static assets, single compiled binary. - AJAX-driven inventory tree: lazy-loaded folder expansion with per-user persisted expand state, drag-and-drop move for folders/assets, safe delete-with-relocate-or-cascade confirmation, search with breadcrumbs. - Assets: CRUD, duplicate, move, auto-generated IT-000001-style IDs, CSV import (with optional folder auto-create) and export. - Admin-defined item types with custom fields (text/long_text/number/date/ boolean/dropdown/url/ip_address). - Configurable statuses, session-based auth (bcrypt, secure cookies), admin/user roles, user management. - CLI: serve, version, database migrate, database backup; /healthz; graceful shutdown; Dockerfile/docker-compose/systemd unit; Go test suite.
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package database_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"inventree/internal/database"
|
||||
)
|
||||
|
||||
func TestOpenSetsPragmasAndMigrates(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
db, err := database.Open(filepath.Join(dir, "test.db"))
|
||||
if err != nil {
|
||||
t.Fatalf("open: %v", err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
var journalMode string
|
||||
if err := db.QueryRow(`PRAGMA journal_mode`).Scan(&journalMode); err != nil {
|
||||
t.Fatalf("query journal_mode: %v", err)
|
||||
}
|
||||
if journalMode != "wal" {
|
||||
t.Fatalf("expected WAL journal mode, got %q", journalMode)
|
||||
}
|
||||
|
||||
var fk int
|
||||
if err := db.QueryRow(`PRAGMA foreign_keys`).Scan(&fk); err != nil {
|
||||
t.Fatalf("query foreign_keys: %v", err)
|
||||
}
|
||||
if fk != 1 {
|
||||
t.Fatalf("expected foreign_keys=1, got %d", fk)
|
||||
}
|
||||
|
||||
var userCount int
|
||||
if err := db.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&userCount); err != nil {
|
||||
t.Fatalf("query users: %v", err)
|
||||
}
|
||||
if userCount != 1 {
|
||||
t.Fatalf("expected 1 seeded admin user, got %d", userCount)
|
||||
}
|
||||
|
||||
var statusCount int
|
||||
if err := db.QueryRow(`SELECT COUNT(*) FROM statuses`).Scan(&statusCount); err != nil {
|
||||
t.Fatalf("query statuses: %v", err)
|
||||
}
|
||||
if statusCount != 5 {
|
||||
t.Fatalf("expected 5 seeded statuses, got %d", statusCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMigrateIsIdempotent(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "test.db")
|
||||
|
||||
db1, err := database.Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("first open: %v", err)
|
||||
}
|
||||
db1.Close()
|
||||
|
||||
// Re-opening (and re-migrating) an already-migrated database must not
|
||||
// error or duplicate seed data.
|
||||
db2, err := database.Open(path)
|
||||
if err != nil {
|
||||
t.Fatalf("second open: %v", err)
|
||||
}
|
||||
defer db2.Close()
|
||||
|
||||
var userCount int
|
||||
if err := db2.QueryRow(`SELECT COUNT(*) FROM users`).Scan(&userCount); err != nil {
|
||||
t.Fatalf("query users: %v", err)
|
||||
}
|
||||
if userCount != 1 {
|
||||
t.Fatalf("expected still 1 seeded admin user after reopen, got %d", userCount)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user