test: add installmeta tests

This commit is contained in:
Thales Maciel 2026-04-30 10:49:22 -03:00
parent dea655ce95
commit 7e528f30b3
No known key found for this signature in database
GPG key ID: 33112E6833C34679

View file

@ -1,7 +1,11 @@
package installmeta
import (
"errors"
"os"
"os/user"
"path/filepath"
"strconv"
"testing"
"time"
)
@ -31,6 +35,157 @@ func TestSaveLoadRoundTrip(t *testing.T) {
}
}
func TestSaveCreatesParentDir(t *testing.T) {
path := filepath.Join(t.TempDir(), "nested", "dir", "install.toml")
meta := Metadata{OwnerUser: "dev", OwnerUID: 1, OwnerGID: 1, OwnerHome: "/home/dev"}
if err := Save(path, meta); err != nil {
t.Fatalf("Save: %v", err)
}
if _, err := os.Stat(path); err != nil {
t.Fatalf("file not written: %v", err)
}
}
func TestSaveRejectsInvalidMetadata(t *testing.T) {
path := filepath.Join(t.TempDir(), "install.toml")
if err := Save(path, Metadata{OwnerUID: 1, OwnerGID: 1, OwnerHome: "/home/dev"}); err == nil {
t.Fatal("Save() = nil, want validation error")
}
if _, err := os.Stat(path); !errors.Is(err, os.ErrNotExist) {
t.Fatalf("Save wrote a file despite validation error: stat err = %v", err)
}
}
func TestLoadMissingFile(t *testing.T) {
_, err := Load(filepath.Join(t.TempDir(), "missing.toml"))
if !errors.Is(err, os.ErrNotExist) {
t.Fatalf("Load() = %v, want os.ErrNotExist", err)
}
}
func TestLoadInvalidTOML(t *testing.T) {
path := filepath.Join(t.TempDir(), "install.toml")
if err := os.WriteFile(path, []byte("not = valid = toml\n"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := Load(path); err == nil {
t.Fatal("Load() = nil, want TOML parse error")
}
}
func TestLoadRejectsInvalidPersistedMetadata(t *testing.T) {
// File parses but fails Validate (no owner_user) — Load must surface
// the validation error rather than returning a zero-value Metadata.
path := filepath.Join(t.TempDir(), "install.toml")
if err := os.WriteFile(path, []byte("owner_uid = 1\nowner_gid = 1\nowner_home = \"/home/dev\"\n"), 0o644); err != nil {
t.Fatal(err)
}
if _, err := Load(path); err == nil {
t.Fatal("Load() = nil, want validation error")
}
}
func TestValidate(t *testing.T) {
tests := []struct {
name string
m Metadata
ok bool
}{
{"valid", Metadata{OwnerUser: "dev", OwnerUID: 1, OwnerGID: 1, OwnerHome: "/home/dev"}, true},
{"missing owner_user", Metadata{OwnerUID: 1, OwnerGID: 1, OwnerHome: "/home/dev"}, false},
{"whitespace owner_user", Metadata{OwnerUser: " ", OwnerUID: 1, OwnerGID: 1, OwnerHome: "/home/dev"}, false},
{"negative uid", Metadata{OwnerUser: "dev", OwnerUID: -1, OwnerGID: 1, OwnerHome: "/home/dev"}, false},
{"negative gid", Metadata{OwnerUser: "dev", OwnerUID: 1, OwnerGID: -1, OwnerHome: "/home/dev"}, false},
{"empty home", Metadata{OwnerUser: "dev", OwnerUID: 1, OwnerGID: 1, OwnerHome: ""}, false},
{"relative home", Metadata{OwnerUser: "dev", OwnerUID: 1, OwnerGID: 1, OwnerHome: "home/dev"}, false},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.m.Validate()
if tc.ok && err != nil {
t.Fatalf("Validate() = %v, want nil", err)
}
if !tc.ok && err == nil {
t.Fatal("Validate() = nil, want error")
}
})
}
}
func TestLookupOwnerEmpty(t *testing.T) {
if _, err := LookupOwner(""); err == nil {
t.Fatal("LookupOwner(\"\") = nil, want error")
}
if _, err := LookupOwner(" "); err == nil {
t.Fatal("LookupOwner(\" \") = nil, want error")
}
}
func TestLookupOwnerMissing(t *testing.T) {
if _, err := LookupOwner("definitely-no-such-user-banger-test"); err == nil {
t.Fatal("LookupOwner(missing) = nil, want error")
}
}
func TestLookupOwnerCurrentUser(t *testing.T) {
cur, err := user.Current()
if err != nil {
t.Skipf("user.Current: %v", err)
}
got, err := LookupOwner(cur.Username)
if err != nil {
t.Fatalf("LookupOwner(%q): %v", cur.Username, err)
}
wantUID, _ := strconv.Atoi(cur.Uid)
wantGID, _ := strconv.Atoi(cur.Gid)
if got.OwnerUser != cur.Username || got.OwnerUID != wantUID || got.OwnerGID != wantGID || got.OwnerHome != cur.HomeDir {
t.Fatalf("LookupOwner = %+v, want user=%s uid=%d gid=%d home=%s",
got, cur.Username, wantUID, wantGID, cur.HomeDir)
}
}
func TestUpdateBuildInfo(t *testing.T) {
path := filepath.Join(t.TempDir(), "install.toml")
original := Metadata{
OwnerUser: "dev",
OwnerUID: 1000,
OwnerGID: 1000,
OwnerHome: "/home/dev",
InstalledAt: time.Unix(1710000000, 0).UTC(),
Version: "v0.1.0",
Commit: "old",
BuiltAt: "2026-01-01T00:00:00Z",
}
if err := Save(path, original); err != nil {
t.Fatalf("Save: %v", err)
}
if err := UpdateBuildInfo(path, " v0.2.0 ", " new ", " 2026-04-30T00:00:00Z "); err != nil {
t.Fatalf("UpdateBuildInfo: %v", err)
}
got, err := Load(path)
if err != nil {
t.Fatalf("Load: %v", err)
}
if got.Version != "v0.2.0" || got.Commit != "new" || got.BuiltAt != "2026-04-30T00:00:00Z" {
t.Fatalf("build fields = %q/%q/%q, want trimmed values", got.Version, got.Commit, got.BuiltAt)
}
// Identity must be preserved.
if got.OwnerUser != original.OwnerUser || got.OwnerUID != original.OwnerUID ||
got.OwnerGID != original.OwnerGID || got.OwnerHome != original.OwnerHome ||
!got.InstalledAt.Equal(original.InstalledAt) {
t.Fatalf("identity changed: got %+v, want %+v", got, original)
}
}
func TestUpdateBuildInfoMissingFile(t *testing.T) {
err := UpdateBuildInfo(filepath.Join(t.TempDir(), "missing.toml"), "v1", "c", "t")
if !errors.Is(err, os.ErrNotExist) {
t.Fatalf("UpdateBuildInfo() = %v, want os.ErrNotExist", err)
}
}
func TestValidateRejectsMissingOwner(t *testing.T) {
err := Metadata{OwnerUID: 1000, OwnerGID: 1000, OwnerHome: "/home/dev"}.Validate()
if err == nil {