github.com/remobjects/goldbaselibrary@v0.0.0-20230924164425-d458680a936b/Source/Gold/log/syslog/syslog_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !windows,!nacl,!plan9,!js 6 7 package syslog 8 9 import ( 10 "bufio" 11 "fmt" 12 "io" 13 "io/ioutil" 14 "log" 15 "net" 16 "os" 17 "runtime" 18 "sync" 19 "testing" 20 "time" 21 ) 22 23 func runPktSyslog(c net.PacketConn, done chan<- string) { 24 var buf [4096]byte 25 var rcvd string 26 ct := 0 27 for { 28 var n int 29 var err error 30 31 c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) 32 n, _, err = c.ReadFrom(buf[:]) 33 rcvd += string(buf[:n]) 34 if err != nil { 35 if oe, ok := err.(*net.OpError); ok { 36 if ct < 3 && oe.Temporary() { 37 ct++ 38 continue 39 } 40 } 41 break 42 } 43 } 44 c.Close() 45 done <- rcvd 46 } 47 48 var crashy = false 49 50 func testableNetwork(network string) bool { 51 switch network { 52 case "unix", "unixgram": 53 switch runtime.GOOS { 54 case "darwin": 55 switch runtime.GOARCH { 56 case "arm", "arm64": 57 return false 58 } 59 case "android": 60 return false 61 } 62 } 63 return true 64 } 65 66 func runStreamSyslog(l net.Listener, done chan<- string, wg *sync.WaitGroup) { 67 for { 68 var c net.Conn 69 var err error 70 if c, err = l.Accept(); err != nil { 71 return 72 } 73 wg.Add(1) 74 go func(c net.Conn) { 75 defer wg.Done() 76 c.SetReadDeadline(time.Now().Add(5 * time.Second)) 77 b := bufio.NewReader(c) 78 for ct := 1; !crashy || ct&7 != 0; ct++ { 79 s, err := b.ReadString('\n') 80 if err != nil { 81 break 82 } 83 done <- s 84 } 85 c.Close() 86 }(c) 87 } 88 } 89 90 func startServer(n, la string, done chan<- string) (addr string, sock io.Closer, wg *sync.WaitGroup) { 91 if n == "udp" || n == "tcp" { 92 la = "127.0.0.1:0" 93 } else { 94 // unix and unixgram: choose an address if none given 95 if la == "" { 96 // use ioutil.TempFile to get a name that is unique 97 f, err := ioutil.TempFile("", "syslogtest") 98 if err != nil { 99 log.Fatal("TempFile: ", err) 100 } 101 f.Close() 102 la = f.Name() 103 } 104 os.Remove(la) 105 } 106 107 wg = new(sync.WaitGroup) 108 if n == "udp" || n == "unixgram" { 109 l, e := net.ListenPacket(n, la) 110 if e != nil { 111 log.Fatalf("startServer failed: %v", e) 112 } 113 addr = l.LocalAddr().String() 114 sock = l 115 wg.Add(1) 116 go func() { 117 defer wg.Done() 118 runPktSyslog(l, done) 119 }() 120 } else { 121 l, e := net.Listen(n, la) 122 if e != nil { 123 log.Fatalf("startServer failed: %v", e) 124 } 125 addr = l.Addr().String() 126 sock = l 127 wg.Add(1) 128 go func() { 129 defer wg.Done() 130 runStreamSyslog(l, done, wg) 131 }() 132 } 133 return 134 } 135 136 func TestWithSimulated(t *testing.T) { 137 t.Parallel() 138 msg := "Test 123" 139 var transport []string 140 for _, n := range []string{"unix", "unixgram", "udp", "tcp"} { 141 if testableNetwork(n) { 142 transport = append(transport, n) 143 } 144 } 145 146 for _, tr := range transport { 147 done := make(chan string) 148 addr, sock, srvWG := startServer(tr, "", done) 149 defer srvWG.Wait() 150 defer sock.Close() 151 if tr == "unix" || tr == "unixgram" { 152 defer os.Remove(addr) 153 } 154 s, err := Dial(tr, addr, LOG_INFO|LOG_USER, "syslog_test") 155 if err != nil { 156 t.Fatalf("Dial() failed: %v", err) 157 } 158 err = s.Info(msg) 159 if err != nil { 160 t.Fatalf("log failed: %v", err) 161 } 162 check(t, msg, <-done) 163 s.Close() 164 } 165 } 166 167 func TestFlap(t *testing.T) { 168 net := "unix" 169 if !testableNetwork(net) { 170 t.Skipf("skipping on %s/%s; 'unix' is not supported", runtime.GOOS, runtime.GOARCH) 171 } 172 173 done := make(chan string) 174 addr, sock, srvWG := startServer(net, "", done) 175 defer srvWG.Wait() 176 defer os.Remove(addr) 177 defer sock.Close() 178 179 s, err := Dial(net, addr, LOG_INFO|LOG_USER, "syslog_test") 180 if err != nil { 181 t.Fatalf("Dial() failed: %v", err) 182 } 183 msg := "Moo 2" 184 err = s.Info(msg) 185 if err != nil { 186 t.Fatalf("log failed: %v", err) 187 } 188 check(t, msg, <-done) 189 190 // restart the server 191 _, sock2, srvWG2 := startServer(net, addr, done) 192 defer srvWG2.Wait() 193 defer sock2.Close() 194 195 // and try retransmitting 196 msg = "Moo 3" 197 err = s.Info(msg) 198 if err != nil { 199 t.Fatalf("log failed: %v", err) 200 } 201 check(t, msg, <-done) 202 203 s.Close() 204 } 205 206 func TestNew(t *testing.T) { 207 if LOG_LOCAL7 != 23<<3 { 208 t.Fatalf("LOG_LOCAL7 has wrong value") 209 } 210 if testing.Short() { 211 // Depends on syslog daemon running, and sometimes it's not. 212 t.Skip("skipping syslog test during -short") 213 } 214 215 s, err := New(LOG_INFO|LOG_USER, "the_tag") 216 if err != nil { 217 if err.Error() == "Unix syslog delivery error" { 218 t.Skip("skipping: syslogd not running") 219 } 220 t.Fatalf("New() failed: %s", err) 221 } 222 // Don't send any messages. 223 s.Close() 224 } 225 226 func TestNewLogger(t *testing.T) { 227 if testing.Short() { 228 t.Skip("skipping syslog test during -short") 229 } 230 f, err := NewLogger(LOG_USER|LOG_INFO, 0) 231 if f == nil { 232 if err.Error() == "Unix syslog delivery error" { 233 t.Skip("skipping: syslogd not running") 234 } 235 t.Error(err) 236 } 237 } 238 239 func TestDial(t *testing.T) { 240 if testing.Short() { 241 t.Skip("skipping syslog test during -short") 242 } 243 f, err := Dial("", "", (LOG_LOCAL7|LOG_DEBUG)+1, "syslog_test") 244 if f != nil { 245 t.Fatalf("Should have trapped bad priority") 246 } 247 f, err = Dial("", "", -1, "syslog_test") 248 if f != nil { 249 t.Fatalf("Should have trapped bad priority") 250 } 251 l, err := Dial("", "", LOG_USER|LOG_ERR, "syslog_test") 252 if err != nil { 253 if err.Error() == "Unix syslog delivery error" { 254 t.Skip("skipping: syslogd not running") 255 } 256 t.Fatalf("Dial() failed: %s", err) 257 } 258 l.Close() 259 } 260 261 func check(t *testing.T, in, out string) { 262 tmpl := fmt.Sprintf("<%d>%%s %%s syslog_test[%%d]: %s\n", LOG_USER+LOG_INFO, in) 263 if hostname, err := os.Hostname(); err != nil { 264 t.Error("Error retrieving hostname") 265 } else { 266 var parsedHostname, timestamp string 267 var pid int 268 if n, err := fmt.Sscanf(out, tmpl, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname { 269 t.Errorf("Got %q, does not match template %q (%d %s)", out, tmpl, n, err) 270 } 271 } 272 } 273 274 func TestWrite(t *testing.T) { 275 t.Parallel() 276 tests := []struct { 277 pri Priority 278 pre string 279 msg string 280 exp string 281 }{ 282 {LOG_USER | LOG_ERR, "syslog_test", "", "%s %s syslog_test[%d]: \n"}, 283 {LOG_USER | LOG_ERR, "syslog_test", "write test", "%s %s syslog_test[%d]: write test\n"}, 284 // Write should not add \n if there already is one 285 {LOG_USER | LOG_ERR, "syslog_test", "write test 2\n", "%s %s syslog_test[%d]: write test 2\n"}, 286 } 287 288 if hostname, err := os.Hostname(); err != nil { 289 t.Fatalf("Error retrieving hostname") 290 } else { 291 for _, test := range tests { 292 done := make(chan string) 293 addr, sock, srvWG := startServer("udp", "", done) 294 defer srvWG.Wait() 295 defer sock.Close() 296 l, err := Dial("udp", addr, test.pri, test.pre) 297 if err != nil { 298 t.Fatalf("syslog.Dial() failed: %v", err) 299 } 300 defer l.Close() 301 _, err = io.WriteString(l, test.msg) 302 if err != nil { 303 t.Fatalf("WriteString() failed: %v", err) 304 } 305 rcvd := <-done 306 test.exp = fmt.Sprintf("<%d>", test.pri) + test.exp 307 var parsedHostname, timestamp string 308 var pid int 309 if n, err := fmt.Sscanf(rcvd, test.exp, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname { 310 t.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, test.exp, n, err) 311 } 312 } 313 } 314 } 315 316 func TestConcurrentWrite(t *testing.T) { 317 addr, sock, srvWG := startServer("udp", "", make(chan string, 1)) 318 defer srvWG.Wait() 319 defer sock.Close() 320 w, err := Dial("udp", addr, LOG_USER|LOG_ERR, "how's it going?") 321 if err != nil { 322 t.Fatalf("syslog.Dial() failed: %v", err) 323 } 324 var wg sync.WaitGroup 325 for i := 0; i < 10; i++ { 326 wg.Add(1) 327 go func() { 328 defer wg.Done() 329 err := w.Info("test") 330 if err != nil { 331 t.Errorf("Info() failed: %v", err) 332 return 333 } 334 }() 335 } 336 wg.Wait() 337 } 338 339 func TestConcurrentReconnect(t *testing.T) { 340 crashy = true 341 defer func() { crashy = false }() 342 343 const N = 10 344 const M = 100 345 net := "unix" 346 if !testableNetwork(net) { 347 net = "tcp" 348 if !testableNetwork(net) { 349 t.Skipf("skipping on %s/%s; neither 'unix' or 'tcp' is supported", runtime.GOOS, runtime.GOARCH) 350 } 351 } 352 done := make(chan string, N*M) 353 addr, sock, srvWG := startServer(net, "", done) 354 if net == "unix" { 355 defer os.Remove(addr) 356 } 357 358 // count all the messages arriving 359 count := make(chan int) 360 go func() { 361 ct := 0 362 for range done { 363 ct++ 364 // we are looking for 500 out of 1000 events 365 // here because lots of log messages are lost 366 // in buffers (kernel and/or bufio) 367 if ct > N*M/2 { 368 break 369 } 370 } 371 count <- ct 372 }() 373 374 var wg sync.WaitGroup 375 wg.Add(N) 376 for i := 0; i < N; i++ { 377 go func() { 378 defer wg.Done() 379 w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag") 380 if err != nil { 381 t.Errorf("syslog.Dial() failed: %v", err) 382 return 383 } 384 defer w.Close() 385 for i := 0; i < M; i++ { 386 err := w.Info("test") 387 if err != nil { 388 t.Errorf("Info() failed: %v", err) 389 return 390 } 391 } 392 }() 393 } 394 wg.Wait() 395 sock.Close() 396 srvWG.Wait() 397 close(done) 398 399 select { 400 case <-count: 401 case <-time.After(100 * time.Millisecond): 402 t.Error("timeout in concurrent reconnect") 403 } 404 }