183 lines
4.4 KiB
Go
183 lines
4.4 KiB
Go
package cache
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestShortcutRejectsAmbiguousTargets(t *testing.T) {
|
|
c := New("", 3600)
|
|
c.Upsert(Entry{Name: "web.prod.example", IP: "10.0.0.1"})
|
|
c.Upsert(Entry{Name: "web.dev.example", IP: "10.0.0.2"})
|
|
normalize := func(s string) string { return strings.SplitN(s, ".", 2)[0] }
|
|
for range 100 {
|
|
entry, found, fresh, err := c.GetByShortcut("web", normalize)
|
|
if err == nil || found || fresh || entry.Name != "" {
|
|
t.Fatalf("ambiguous shortcut returned target: %+v, %v, %v, %v", entry, found, fresh, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSaveMergesIndependentlyLoadedCaches(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "hosts.json")
|
|
a, b := New(path, 3600), New(path, 3600)
|
|
for _, c := range []*Cache{a, b} {
|
|
if err := c.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
a.Upsert(Entry{Name: "a", IP: "10.0.0.1"})
|
|
b.Upsert(Entry{Name: "b", IP: "10.0.0.2"})
|
|
for _, c := range []*Cache{a, b} {
|
|
if err := c.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := a.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(a.All()) != 2 {
|
|
t.Fatalf("lost an update: %+v", a.All())
|
|
}
|
|
|
|
// Saving a stale usage update must retain newer IPs and both usage times.
|
|
if err := b.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b.MarkUsed("a")
|
|
used, _ := b.Get("a")
|
|
a.Upsert(Entry{Name: "a", IP: "10.0.0.3"})
|
|
if err := a.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := b.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, _ := b.Get("a")
|
|
if got.IP != "10.0.0.3" || !got.LastUsed.Equal(used.LastUsed) {
|
|
t.Fatalf("lost refreshed IP or usage: %+v", got)
|
|
}
|
|
|
|
b.Delete("a")
|
|
if err := b.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := a.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got, _ := a.Get("a"); got.Name != "" {
|
|
t.Fatalf("deleted entry survived: %+v", got)
|
|
}
|
|
a.Clear()
|
|
if err := a.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := b.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(b.All()) != 0 {
|
|
t.Fatal("clear merged old entries back in")
|
|
}
|
|
}
|
|
|
|
func TestSaveAcrossProcesses(t *testing.T) {
|
|
if path := os.Getenv("NETSSH_TEST_CACHE_WRITER_PATH"); path != "" {
|
|
c := New(path, 3600)
|
|
if err := c.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c.Upsert(Entry{Name: os.Getenv("NETSSH_TEST_CACHE_WRITER_NAME"), IP: "10.0.0.1"})
|
|
if err := c.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return
|
|
}
|
|
path := filepath.Join(t.TempDir(), "hosts.json")
|
|
const writers = 8
|
|
cmds := make([]*exec.Cmd, writers)
|
|
for i := range cmds {
|
|
cmd := exec.Command(os.Args[0], "-test.run=^TestSaveAcrossProcesses$")
|
|
cmd.Env = append(os.Environ(), "NETSSH_TEST_CACHE_WRITER_PATH="+path, fmt.Sprintf("NETSSH_TEST_CACHE_WRITER_NAME=host-%d", i))
|
|
cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cmds[i] = cmd
|
|
}
|
|
for _, cmd := range cmds {
|
|
if err := cmd.Wait(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
c := New(path, 3600)
|
|
if err := c.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(c.All()) != writers {
|
|
t.Fatalf("lost concurrent updates: got %d, want %d", len(c.All()), writers)
|
|
}
|
|
}
|
|
|
|
func TestSavePreservesNewerUsageFromDisk(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "hosts.json")
|
|
a := New(path, 3600)
|
|
a.Upsert(Entry{Name: "web", IP: "10.0.0.1", LastUsed: time.Now()})
|
|
if err := a.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b := New(path, 3600)
|
|
if err := b.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
a.MarkUsed("web")
|
|
used, _ := a.Get("web")
|
|
if err := a.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b.Upsert(Entry{Name: "web", IP: "10.0.0.2"})
|
|
if err := b.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, _ := b.Get("web")
|
|
if got.IP != "10.0.0.2" || !got.LastUsed.Equal(used.LastUsed) {
|
|
t.Fatalf("lost data: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestUsageSaveDoesNotRestoreRemovedHosts(t *testing.T) {
|
|
for _, clear := range []bool{false, true} {
|
|
t.Run(fmt.Sprintf("clear=%v", clear), func(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "hosts.json")
|
|
a := New(path, 3600)
|
|
a.Upsert(Entry{Name: "web", IP: "10.0.0.1"})
|
|
if err := a.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b := New(path, 3600)
|
|
if err := b.Load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
b.MarkUsed("web")
|
|
if clear {
|
|
a.Clear()
|
|
} else {
|
|
a.Delete("web")
|
|
}
|
|
if err := a.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := b.Save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(b.All()) != 0 {
|
|
t.Fatalf("usage update restored removed entry: %+v", b.All())
|
|
}
|
|
})
|
|
}
|
|
}
|