summaryrefslogtreecommitdiff
path: root/src/log/syslog/syslog_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/log/syslog/syslog_test.go')
-rw-r--r--src/log/syslog/syslog_test.go358
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, &timestamp, &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, &timestamp, &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")
+ }
+}