diff options
author | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
---|---|---|
committer | Tianon Gravi <admwiggin@gmail.com> | 2015-01-15 11:54:00 -0700 |
commit | f154da9e12608589e8d5f0508f908a0c3e88a1bb (patch) | |
tree | f8255d51e10c6f1e0ed69702200b966c9556a431 /src/log/syslog/syslog_test.go | |
parent | 8d8329ed5dfb9622c82a9fbec6fd99a580f9c9f6 (diff) | |
download | golang-upstream/1.4.tar.gz |
Imported Upstream version 1.4upstream/1.4
Diffstat (limited to 'src/log/syslog/syslog_test.go')
-rw-r--r-- | src/log/syslog/syslog_test.go | 358 |
1 files changed, 358 insertions, 0 deletions
diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go new file mode 100644 index 000000000..6a863fed3 --- /dev/null +++ b/src/log/syslog/syslog_test.go @@ -0,0 +1,358 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !windows,!nacl,!plan9 + +package syslog + +import ( + "bufio" + "fmt" + "io" + "io/ioutil" + "log" + "net" + "os" + "sync" + "testing" + "time" +) + +func runPktSyslog(c net.PacketConn, done chan<- string) { + var buf [4096]byte + var rcvd string + ct := 0 + for { + var n int + var err error + + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + n, _, err = c.ReadFrom(buf[:]) + rcvd += string(buf[:n]) + if err != nil { + if oe, ok := err.(*net.OpError); ok { + if ct < 3 && oe.Temporary() { + ct++ + continue + } + } + break + } + } + c.Close() + done <- rcvd +} + +var crashy = false + +func runStreamSyslog(l net.Listener, done chan<- string, wg *sync.WaitGroup) { + for { + var c net.Conn + var err error + if c, err = l.Accept(); err != nil { + return + } + wg.Add(1) + go func(c net.Conn) { + defer wg.Done() + c.SetReadDeadline(time.Now().Add(5 * time.Second)) + b := bufio.NewReader(c) + for ct := 1; !crashy || ct&7 != 0; ct++ { + s, err := b.ReadString('\n') + if err != nil { + break + } + done <- s + } + c.Close() + }(c) + } +} + +func startServer(n, la string, done chan<- string) (addr string, sock io.Closer, wg *sync.WaitGroup) { + if n == "udp" || n == "tcp" { + la = "127.0.0.1:0" + } else { + // unix and unixgram: choose an address if none given + if la == "" { + // use ioutil.TempFile to get a name that is unique + f, err := ioutil.TempFile("", "syslogtest") + if err != nil { + log.Fatal("TempFile: ", err) + } + f.Close() + la = f.Name() + } + os.Remove(la) + } + + wg = new(sync.WaitGroup) + if n == "udp" || n == "unixgram" { + l, e := net.ListenPacket(n, la) + if e != nil { + log.Fatalf("startServer failed: %v", e) + } + addr = l.LocalAddr().String() + sock = l + wg.Add(1) + go func() { + defer wg.Done() + runPktSyslog(l, done) + }() + } else { + l, e := net.Listen(n, la) + if e != nil { + log.Fatalf("startServer failed: %v", e) + } + addr = l.Addr().String() + sock = l + wg.Add(1) + go func() { + defer wg.Done() + runStreamSyslog(l, done, wg) + }() + } + return +} + +func TestWithSimulated(t *testing.T) { + msg := "Test 123" + transport := []string{"unix", "unixgram", "udp", "tcp"} + + for _, tr := range transport { + done := make(chan string) + addr, sock, srvWG := startServer(tr, "", done) + defer srvWG.Wait() + defer sock.Close() + if tr == "unix" || tr == "unixgram" { + defer os.Remove(addr) + } + s, err := Dial(tr, addr, LOG_INFO|LOG_USER, "syslog_test") + if err != nil { + t.Fatalf("Dial() failed: %v", err) + } + err = s.Info(msg) + if err != nil { + t.Fatalf("log failed: %v", err) + } + check(t, msg, <-done) + s.Close() + } +} + +func TestFlap(t *testing.T) { + net := "unix" + done := make(chan string) + addr, sock, srvWG := startServer(net, "", done) + defer srvWG.Wait() + defer os.Remove(addr) + defer sock.Close() + + s, err := Dial(net, addr, LOG_INFO|LOG_USER, "syslog_test") + if err != nil { + t.Fatalf("Dial() failed: %v", err) + } + msg := "Moo 2" + err = s.Info(msg) + if err != nil { + t.Fatalf("log failed: %v", err) + } + check(t, msg, <-done) + + // restart the server + _, sock2, srvWG2 := startServer(net, addr, done) + defer srvWG2.Wait() + defer sock2.Close() + + // and try retransmitting + msg = "Moo 3" + err = s.Info(msg) + if err != nil { + t.Fatalf("log failed: %v", err) + } + check(t, msg, <-done) + + s.Close() +} + +func TestNew(t *testing.T) { + if LOG_LOCAL7 != 23<<3 { + t.Fatalf("LOG_LOCAL7 has wrong value") + } + if testing.Short() { + // Depends on syslog daemon running, and sometimes it's not. + t.Skip("skipping syslog test during -short") + } + + s, err := New(LOG_INFO|LOG_USER, "the_tag") + if err != nil { + t.Fatalf("New() failed: %s", err) + } + // Don't send any messages. + s.Close() +} + +func TestNewLogger(t *testing.T) { + if testing.Short() { + t.Skip("skipping syslog test during -short") + } + f, err := NewLogger(LOG_USER|LOG_INFO, 0) + if f == nil { + t.Error(err) + } +} + +func TestDial(t *testing.T) { + if testing.Short() { + t.Skip("skipping syslog test during -short") + } + f, err := Dial("", "", (LOG_LOCAL7|LOG_DEBUG)+1, "syslog_test") + if f != nil { + t.Fatalf("Should have trapped bad priority") + } + f, err = Dial("", "", -1, "syslog_test") + if f != nil { + t.Fatalf("Should have trapped bad priority") + } + l, err := Dial("", "", LOG_USER|LOG_ERR, "syslog_test") + if err != nil { + t.Fatalf("Dial() failed: %s", err) + } + l.Close() +} + +func check(t *testing.T, in, out string) { + tmpl := fmt.Sprintf("<%d>%%s %%s syslog_test[%%d]: %s\n", LOG_USER+LOG_INFO, in) + if hostname, err := os.Hostname(); err != nil { + t.Error("Error retrieving hostname") + } else { + var parsedHostname, timestamp string + var pid int + if n, err := fmt.Sscanf(out, tmpl, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname { + t.Errorf("Got %q, does not match template %q (%d %s)", out, tmpl, n, err) + } + } +} + +func TestWrite(t *testing.T) { + tests := []struct { + pri Priority + pre string + msg string + exp string + }{ + {LOG_USER | LOG_ERR, "syslog_test", "", "%s %s syslog_test[%d]: \n"}, + {LOG_USER | LOG_ERR, "syslog_test", "write test", "%s %s syslog_test[%d]: write test\n"}, + // Write should not add \n if there already is one + {LOG_USER | LOG_ERR, "syslog_test", "write test 2\n", "%s %s syslog_test[%d]: write test 2\n"}, + } + + if hostname, err := os.Hostname(); err != nil { + t.Fatalf("Error retrieving hostname") + } else { + for _, test := range tests { + done := make(chan string) + addr, sock, srvWG := startServer("udp", "", done) + defer srvWG.Wait() + defer sock.Close() + l, err := Dial("udp", addr, test.pri, test.pre) + if err != nil { + t.Fatalf("syslog.Dial() failed: %v", err) + } + defer l.Close() + _, err = io.WriteString(l, test.msg) + if err != nil { + t.Fatalf("WriteString() failed: %v", err) + } + rcvd := <-done + test.exp = fmt.Sprintf("<%d>", test.pri) + test.exp + var parsedHostname, timestamp string + var pid int + if n, err := fmt.Sscanf(rcvd, test.exp, ×tamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname { + t.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, test.exp, n, err) + } + } + } +} + +func TestConcurrentWrite(t *testing.T) { + addr, sock, srvWG := startServer("udp", "", make(chan string, 1)) + defer srvWG.Wait() + defer sock.Close() + w, err := Dial("udp", addr, LOG_USER|LOG_ERR, "how's it going?") + if err != nil { + t.Fatalf("syslog.Dial() failed: %v", err) + } + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + err := w.Info("test") + if err != nil { + t.Errorf("Info() failed: %v", err) + return + } + }() + } + wg.Wait() +} + +func TestConcurrentReconnect(t *testing.T) { + crashy = true + defer func() { crashy = false }() + + const N = 10 + const M = 100 + net := "unix" + done := make(chan string, N*M) + addr, sock, srvWG := startServer(net, "", done) + defer os.Remove(addr) + + // count all the messages arriving + count := make(chan int) + go func() { + ct := 0 + for range done { + ct++ + // we are looking for 500 out of 1000 events + // here because lots of log messages are lost + // in buffers (kernel and/or bufio) + if ct > N*M/2 { + break + } + } + count <- ct + }() + + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag") + if err != nil { + t.Fatalf("syslog.Dial() failed: %v", err) + } + defer w.Close() + for i := 0; i < M; i++ { + err := w.Info("test") + if err != nil { + t.Errorf("Info() failed: %v", err) + return + } + } + }() + } + wg.Wait() + sock.Close() + srvWG.Wait() + close(done) + + select { + case <-count: + case <-time.After(100 * time.Millisecond): + t.Error("timeout in concurrent reconnect") + } +} |