github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/launchd/launchd_test.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 //go:build darwin 5 // +build darwin 6 7 package launchd 8 9 import ( 10 "encoding/xml" 11 "fmt" 12 "math/rand" 13 "os" 14 "testing" 15 "time" 16 17 "github.com/keybase/client/go/utils" 18 ) 19 20 func validExecutableForTest() (string, error) { 21 return utils.BinPath() 22 } 23 24 func TestPlist(t *testing.T) { 25 binPath, err := validExecutableForTest() 26 if err != nil { 27 t.Fatal(err) 28 } 29 envVars := []EnvVar{ 30 NewEnvVar("TESTVAR1", "1"), 31 NewEnvVar("TESTVAR2", "2"), 32 } 33 plist := NewPlist("keybase.testing", binPath, []string{"--flag=test", "testArg"}, envVars, "keybase.testing.log", "This is a comment") 34 35 data := plist.plistXML() 36 t.Logf("Plist: %s\n", data) 37 38 var i interface{} 39 // This tests valid XML but not actual values 40 err = xml.Unmarshal([]byte(data), &i) 41 if err != nil { 42 t.Errorf("Bad plist: %s", err) 43 } 44 } 45 46 func TestCheckPlist(t *testing.T) { 47 label := fmt.Sprintf("keybase.testing.checkplist.%s", randStringBytes(32)) 48 t.Logf("Label: %s", label) 49 service := NewService(label) 50 defer os.Remove(service.plistDestination()) 51 52 binPath, err := validExecutableForTest() 53 if err != nil { 54 t.Fatal(err) 55 } 56 envVars := []EnvVar{ 57 NewEnvVar("TESTVAR1", "1"), 58 NewEnvVar("TESTVAR2", "2"), 59 } 60 plist := NewPlist(label, binPath, []string{}, envVars, "keybase.testing.log", "") 61 plistIsValid, err := service.CheckPlist(plist) 62 if err != nil { 63 t.Fatal(err) 64 } 65 if plistIsValid { 66 t.Fatalf("We shouldn't have a plist") 67 } 68 69 err = service.savePlist(plist) 70 if err != nil { 71 t.Fatal(err) 72 } 73 74 // Check valid plist after save 75 plistIsValidAfter, err := service.CheckPlist(plist) 76 if err != nil { 77 t.Fatal(err) 78 } 79 if !plistIsValidAfter { 80 t.Fatalf("Plist was invalid after install") 81 } 82 83 // Check a new plist 84 plistNew := NewPlist(label, binPath, []string{"differentArgs"}, envVars, "keybase.testing.log", "") 85 plistNewIsValid, err := service.CheckPlist(plistNew) 86 if err != nil { 87 t.Fatal(err) 88 } 89 if plistNewIsValid { 90 t.Fatal("New plist should be invalid") 91 } 92 93 err = service.savePlist(plistNew) 94 if err != nil { 95 t.Fatal(err) 96 } 97 98 plistNewIsValidAfterInstall, err := service.CheckPlist(plistNew) 99 if err != nil { 100 t.Fatal(err) 101 } 102 if !plistNewIsValidAfterInstall { 103 t.Fatalf("New plist should be valid after install") 104 } 105 } 106 107 func randStringBytes(n int) string { 108 const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 109 b := make([]byte, n) 110 for i := range b { 111 b[i] = letterBytes[rand.Intn(len(letterBytes))] 112 } 113 return string(b) 114 } 115 116 func TestWaitForStatusOK(t *testing.T) { 117 fn := func() (*ServiceStatus, error) { 118 return &ServiceStatus{label: "ok", pid: "1"}, nil 119 } 120 status, err := waitForStatus(time.Second, time.Millisecond, fn) 121 if err != nil { 122 t.Fatal(err) 123 } 124 if status == nil || status.label != "ok" { 125 t.Fatalf("Invalid status") 126 } 127 } 128 129 func TestWaitForStatusDelayed(t *testing.T) { 130 i := 0 131 fn := func() (*ServiceStatus, error) { 132 i++ 133 if i == 5 { 134 return &ServiceStatus{label: "ok_delayed", pid: "1"}, nil 135 } 136 return nil, nil 137 } 138 status, err := waitForStatus(time.Second, time.Millisecond, fn) 139 if err != nil { 140 t.Fatal(err) 141 } 142 if status == nil { 143 t.Fatalf("Wait timed out") 144 } 145 if status.label != "ok_delayed" { 146 t.Fatalf("Invalid status") 147 } 148 } 149 150 func TestWaitForStatusErrored(t *testing.T) { 151 fn := func() (*ServiceStatus, error) { 152 return nil, fmt.Errorf("status error") 153 } 154 _, err := waitForStatus(time.Second, time.Millisecond, fn) 155 if err == nil { 156 t.Fatal("Expected error") 157 } 158 if err.Error() != "status error" { 159 t.Fatal("Expected error returned from fn above") 160 } 161 } 162 163 func TestWaitForStatusTimeout(t *testing.T) { 164 fn := func() (*ServiceStatus, error) { 165 return nil, nil 166 } 167 status, err := waitForStatus(5*time.Millisecond, time.Millisecond, fn) 168 if err != nil { 169 t.Fatal(err) 170 } 171 if status != nil { 172 t.Fatalf("Status should be nil (timed out): %#v", status) 173 } 174 } 175 176 func TestWaitForExitOK(t *testing.T) { 177 fn := func() (*ServiceStatus, error) { 178 return nil, nil 179 } 180 err := waitForExit(time.Second, time.Millisecond, fn) 181 if err != nil { 182 t.Fatal(err) 183 } 184 } 185 186 func TestWaitForExitDelayed(t *testing.T) { 187 i := 0 188 fn := func() (*ServiceStatus, error) { 189 i++ 190 if i < 5 { 191 return &ServiceStatus{label: "ok", pid: "1"}, nil 192 } 193 return nil, nil 194 } 195 err := waitForExit(time.Second, time.Millisecond, fn) 196 if err != nil { 197 t.Fatal(err) 198 } 199 } 200 201 func TestWaitForExitErrored(t *testing.T) { 202 fn := func() (*ServiceStatus, error) { 203 return nil, fmt.Errorf("status error") 204 } 205 err := waitForExit(time.Second, time.Millisecond, fn) 206 if err == nil { 207 t.Fatal("Expected error") 208 } 209 } 210 211 func TestWaitForExitTimeout(t *testing.T) { 212 fn := func() (*ServiceStatus, error) { 213 return &ServiceStatus{label: "never_exit", pid: "1"}, nil 214 } 215 err := waitForExit(5*time.Millisecond, time.Millisecond, fn) 216 if err == nil { 217 t.Fatal("Should have timed out") 218 } 219 if err.Error() != "Waiting for service exit timed out" { 220 t.Fatal("Should have timed out error") 221 } 222 }