src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/daemon/activate_test.go (about) 1 package daemon 2 3 import ( 4 "io" 5 "net" 6 "os" 7 "runtime" 8 "testing" 9 "time" 10 11 "src.elv.sh/pkg/daemon/daemondefs" 12 "src.elv.sh/pkg/must" 13 "src.elv.sh/pkg/testutil" 14 ) 15 16 func TestActivate_ConnectsToExistingServer(t *testing.T) { 17 setup(t) 18 startServer(t, cli("sock", "db")) 19 _, err := Activate(io.Discard, 20 &daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."}) 21 if err != nil { 22 t.Errorf("got error %v, want nil", err) 23 } 24 } 25 26 func TestActivate_SpawnsNewServer(t *testing.T) { 27 activated := 0 28 setupForActivate(t, func(name string, argv []string, attr *os.ProcAttr) error { 29 startServer(t, argv) 30 activated++ 31 return nil 32 }) 33 34 _, err := Activate(io.Discard, 35 &daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."}) 36 if err != nil { 37 t.Errorf("got error %v, want nil", err) 38 } 39 if activated != 1 { 40 t.Errorf("got activated %v times, want 1", activated) 41 } 42 } 43 44 func TestActivate_RemovesHangingSocketAndSpawnsNewServer(t *testing.T) { 45 activated := 0 46 setupForActivate(t, func(name string, argv []string, attr *os.ProcAttr) error { 47 startServer(t, argv) 48 activated++ 49 return nil 50 }) 51 makeHangingUnixSocket(t, "sock") 52 53 _, err := Activate(io.Discard, 54 &daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."}) 55 if err != nil { 56 t.Errorf("got error %v, want nil", err) 57 } 58 if activated != 1 { 59 t.Errorf("got activated %v times, want 1", activated) 60 } 61 } 62 63 func TestActivate_FailsIfCannotStatSock(t *testing.T) { 64 setup(t) 65 // Build a path for which Lstat will return a non-nil err such that 66 // os.IsNotExist(err) is false. 67 badSockPath := "" 68 if runtime.GOOS != "windows" { 69 // POSIX lstat(2) returns ENOTDIR instead of ENOENT if a path prefix is 70 // not a directory. 71 must.CreateEmpty("not-dir") 72 badSockPath = "not-dir/sock" 73 } else { 74 // Use a syntactically invalid drive letter on Windows. 75 badSockPath = `CD:\sock` 76 } 77 _, err := Activate(io.Discard, 78 &daemondefs.SpawnConfig{DbPath: "db", SockPath: badSockPath, RunDir: "."}) 79 if err == nil { 80 t.Errorf("got error nil, want non-nil") 81 } 82 } 83 84 func TestActivate_FailsIfCannotDialSock(t *testing.T) { 85 setup(t) 86 must.CreateEmpty("sock") 87 _, err := Activate(io.Discard, 88 &daemondefs.SpawnConfig{DbPath: "db", SockPath: "sock", RunDir: "."}) 89 if err == nil { 90 t.Errorf("got error nil, want non-nil") 91 } 92 } 93 94 func setupForActivate(t *testing.T, f func(string, []string, *os.ProcAttr) error) { 95 setup(t) 96 97 testutil.Set(t, &startProcess, f) 98 scaleDuration(t, &daemonSpawnTimeout) 99 scaleDuration(t, &daemonKillTimeout) 100 } 101 102 func scaleDuration(t *testing.T, d *time.Duration) { 103 testutil.Set(t, d, testutil.Scaled(*d)) 104 } 105 106 func makeHangingUnixSocket(t *testing.T, path string) { 107 t.Helper() 108 109 l, err := net.Listen("unix", path) 110 if err != nil { 111 t.Fatal(err) 112 } 113 // We need to call l.Close() to make the socket hang, but that will 114 // helpfully remove the socket file. Work around this by renaming the socket 115 // file. 116 err = os.Rename(path, path+".save") 117 if err != nil { 118 t.Fatal(err) 119 } 120 l.Close() 121 err = os.Rename(path+".save", path) 122 if err != nil { 123 t.Fatal(err) 124 } 125 }