libgo: Update to Go 1.3 release.
[official-gcc.git] / libgo / go / log / syslog / syslog_test.go
blob24a460f6d9eaaa0b33348e4a1a1c51e946a9d09a
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.
5 // +build !windows,!nacl,!plan9
7 package syslog
9 import (
10 "bufio"
11 "fmt"
12 "io"
13 "io/ioutil"
14 "log"
15 "net"
16 "os"
17 "sync"
18 "testing"
19 "time"
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
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
40 break
43 c.Close()
44 done <- rcvd
47 var crashy = false
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
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
66 done <- s
68 c.Close()
69 }(c)
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)
84 f.Close()
85 la = f.Name()
87 os.Remove(la)
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)
96 addr = l.LocalAddr().String()
97 sock = l
98 wg.Add(1)
99 go func() {
100 defer wg.Done()
101 runPktSyslog(l, done)
103 } else {
104 l, e := net.Listen(n, la)
105 if e != nil {
106 log.Fatalf("startServer failed: %v", e)
108 addr = l.Addr().String()
109 sock = l
110 wg.Add(1)
111 go func() {
112 defer wg.Done()
113 runStreamSyslog(l, done, wg)
116 return
119 func TestWithSimulated(t *testing.T) {
120 msg := "Test 123"
121 transport := []string{"unix", "unixgram", "udp", "tcp"}
123 for _, tr := range transport {
124 done := make(chan string)
125 addr, sock, srvWG := startServer(tr, "", done)
126 defer srvWG.Wait()
127 defer sock.Close()
128 if tr == "unix" || tr == "unixgram" {
129 defer os.Remove(addr)
131 s, err := Dial(tr, addr, LOG_INFO|LOG_USER, "syslog_test")
132 if err != nil {
133 t.Fatalf("Dial() failed: %v", err)
135 err = s.Info(msg)
136 if err != nil {
137 t.Fatalf("log failed: %v", err)
139 check(t, msg, <-done)
140 s.Close()
144 func TestFlap(t *testing.T) {
145 net := "unix"
146 done := make(chan string)
147 addr, sock, srvWG := startServer(net, "", done)
148 defer srvWG.Wait()
149 defer os.Remove(addr)
150 defer sock.Close()
152 s, err := Dial(net, addr, LOG_INFO|LOG_USER, "syslog_test")
153 if err != nil {
154 t.Fatalf("Dial() failed: %v", err)
156 msg := "Moo 2"
157 err = s.Info(msg)
158 if err != nil {
159 t.Fatalf("log failed: %v", err)
161 check(t, msg, <-done)
163 // restart the server
164 _, sock2, srvWG2 := startServer(net, addr, done)
165 defer srvWG2.Wait()
166 defer sock2.Close()
168 // and try retransmitting
169 msg = "Moo 3"
170 err = s.Info(msg)
171 if err != nil {
172 t.Fatalf("log failed: %v", err)
174 check(t, msg, <-done)
176 s.Close()
179 func TestNew(t *testing.T) {
180 if LOG_LOCAL7 != 23<<3 {
181 t.Fatalf("LOG_LOCAL7 has wrong value")
183 if testing.Short() {
184 // Depends on syslog daemon running, and sometimes it's not.
185 t.Skip("skipping syslog test during -short")
188 s, err := New(LOG_INFO|LOG_USER, "the_tag")
189 if err != nil {
190 t.Fatalf("New() failed: %s", err)
192 // Don't send any messages.
193 s.Close()
196 func TestNewLogger(t *testing.T) {
197 if testing.Short() {
198 t.Skip("skipping syslog test during -short")
200 f, err := NewLogger(LOG_USER|LOG_INFO, 0)
201 if f == nil {
202 t.Error(err)
206 func TestDial(t *testing.T) {
207 if testing.Short() {
208 t.Skip("skipping syslog test during -short")
210 f, err := Dial("", "", (LOG_LOCAL7|LOG_DEBUG)+1, "syslog_test")
211 if f != nil {
212 t.Fatalf("Should have trapped bad priority")
214 f, err = Dial("", "", -1, "syslog_test")
215 if f != nil {
216 t.Fatalf("Should have trapped bad priority")
218 l, err := Dial("", "", LOG_USER|LOG_ERR, "syslog_test")
219 if err != nil {
220 t.Fatalf("Dial() failed: %s", err)
222 l.Close()
225 func check(t *testing.T, in, out string) {
226 tmpl := fmt.Sprintf("<%d>%%s %%s syslog_test[%%d]: %s\n", LOG_USER+LOG_INFO, in)
227 if hostname, err := os.Hostname(); err != nil {
228 t.Error("Error retrieving hostname")
229 } else {
230 var parsedHostname, timestamp string
231 var pid int
232 if n, err := fmt.Sscanf(out, tmpl, &timestamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname {
233 t.Errorf("Got %q, does not match template %q (%d %s)", out, tmpl, n, err)
238 func TestWrite(t *testing.T) {
239 tests := []struct {
240 pri Priority
241 pre string
242 msg string
243 exp string
245 {LOG_USER | LOG_ERR, "syslog_test", "", "%s %s syslog_test[%d]: \n"},
246 {LOG_USER | LOG_ERR, "syslog_test", "write test", "%s %s syslog_test[%d]: write test\n"},
247 // Write should not add \n if there already is one
248 {LOG_USER | LOG_ERR, "syslog_test", "write test 2\n", "%s %s syslog_test[%d]: write test 2\n"},
251 if hostname, err := os.Hostname(); err != nil {
252 t.Fatalf("Error retrieving hostname")
253 } else {
254 for _, test := range tests {
255 done := make(chan string)
256 addr, sock, srvWG := startServer("udp", "", done)
257 defer srvWG.Wait()
258 defer sock.Close()
259 l, err := Dial("udp", addr, test.pri, test.pre)
260 if err != nil {
261 t.Fatalf("syslog.Dial() failed: %v", err)
263 defer l.Close()
264 _, err = io.WriteString(l, test.msg)
265 if err != nil {
266 t.Fatalf("WriteString() failed: %v", err)
268 rcvd := <-done
269 test.exp = fmt.Sprintf("<%d>", test.pri) + test.exp
270 var parsedHostname, timestamp string
271 var pid int
272 if n, err := fmt.Sscanf(rcvd, test.exp, &timestamp, &parsedHostname, &pid); n != 3 || err != nil || hostname != parsedHostname {
273 t.Errorf("s.Info() = '%q', didn't match '%q' (%d %s)", rcvd, test.exp, n, err)
279 func TestConcurrentWrite(t *testing.T) {
280 addr, sock, srvWG := startServer("udp", "", make(chan string, 1))
281 defer srvWG.Wait()
282 defer sock.Close()
283 w, err := Dial("udp", addr, LOG_USER|LOG_ERR, "how's it going?")
284 if err != nil {
285 t.Fatalf("syslog.Dial() failed: %v", err)
287 var wg sync.WaitGroup
288 for i := 0; i < 10; i++ {
289 wg.Add(1)
290 go func() {
291 defer wg.Done()
292 err := w.Info("test")
293 if err != nil {
294 t.Errorf("Info() failed: %v", err)
295 return
299 wg.Wait()
302 func TestConcurrentReconnect(t *testing.T) {
303 crashy = true
304 defer func() { crashy = false }()
306 const N = 10
307 const M = 100
308 net := "unix"
309 done := make(chan string, N*M)
310 addr, sock, srvWG := startServer(net, "", done)
311 defer os.Remove(addr)
313 // count all the messages arriving
314 count := make(chan int)
315 go func() {
316 ct := 0
317 for _ = range done {
318 ct++
319 // we are looking for 500 out of 1000 events
320 // here because lots of log messages are lost
321 // in buffers (kernel and/or bufio)
322 if ct > N*M/2 {
323 break
326 count <- ct
329 var wg sync.WaitGroup
330 wg.Add(N)
331 for i := 0; i < N; i++ {
332 go func() {
333 defer wg.Done()
334 w, err := Dial(net, addr, LOG_USER|LOG_ERR, "tag")
335 if err != nil {
336 t.Fatalf("syslog.Dial() failed: %v", err)
338 defer w.Close()
339 for i := 0; i < M; i++ {
340 err := w.Info("test")
341 if err != nil {
342 t.Errorf("Info() failed: %v", err)
343 return
348 wg.Wait()
349 sock.Close()
350 srvWG.Wait()
351 close(done)
353 select {
354 case <-count:
355 case <-time.After(100 * time.Millisecond):
356 t.Error("timeout in concurrent reconnect")