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