Merge branch 'master' into 3761-pull-list-worker
[arvados.git] / services / crunchstat / crunchstat_test.go
1 package main
2
3 import (
4         "bufio"
5         "bytes"
6         "io"
7         "log"
8         "math/rand"
9         "os"
10         "regexp"
11         "testing"
12         "time"
13 )
14
15 func TestReadAllOrWarnFail(t *testing.T) {
16         rcv := captureLogs()
17         defer uncaptureLogs()
18         go func() {
19                 // The special file /proc/self/mem can be opened for
20                 // reading, but reading from byte 0 returns an error.
21                 f, err := os.Open("/proc/self/mem")
22                 if err != nil {
23                         t.Fatalf("Opening /proc/self/mem: %s", err)
24                 }
25                 if x, err := ReadAllOrWarn(f); err == nil {
26                         t.Fatalf("Expected error, got %v", x)
27                 }
28         }()
29         if msg, err := rcv.ReadBytes('\n'); err != nil {
30                 t.Fatal(err)
31         } else if matched, err := regexp.MatchString("^crunchstat: .*error.*", string(msg)); err != nil || !matched {
32                 t.Fatalf("Expected error message about unreadable file, got \"%s\"", msg)
33         }
34 }
35
36 func TestReadAllOrWarnSuccess(t *testing.T) {
37         f, err := os.Open("./crunchstat_test.go")
38         if err != nil {
39                 t.Fatalf("Opening ./crunchstat_test.go: %s", err)
40         }
41         data, err := ReadAllOrWarn(f)
42         if err != nil {
43                 t.Fatalf("got error %s", err)
44         }
45         if matched, err := regexp.MatchString("^package main\n", string(data)); err != nil || !matched {
46                 t.Fatalf("data failed regexp: %s", err)
47         }
48 }
49
50 // Test that CopyPipeToChildLog works even on lines longer than
51 // bufio.MaxScanTokenSize.
52 func TestCopyPipeToChildLogLongLines(t *testing.T) {
53         rcv := captureLogs()
54         defer uncaptureLogs()
55
56         control := make(chan bool)
57         pipeIn, pipeOut := io.Pipe()
58         go CopyPipeToChildLog(pipeIn, control)
59
60         sentBytes := make([]byte, bufio.MaxScanTokenSize+MaxLogLine+(1<<22))
61         go func() {
62                 pipeOut.Write([]byte("before\n"))
63
64                 for i := range sentBytes {
65                         // Some bytes that aren't newlines:
66                         sentBytes[i] = byte((rand.Int() & 0xff) | 0x80)
67                 }
68                 sentBytes[len(sentBytes)-1] = '\n'
69                 pipeOut.Write(sentBytes)
70
71                 pipeOut.Write([]byte("after"))
72                 pipeOut.Close()
73         }()
74
75         if before, err := rcv.ReadBytes('\n'); err != nil || string(before) != "before\n" {
76                 t.Fatalf("\"before\n\" not received (got \"%s\", %s)", before, err)
77         }
78
79         var receivedBytes []byte
80         done := false
81         for !done {
82                 line, err := rcv.ReadBytes('\n')
83                 if err != nil {
84                         t.Fatal(err)
85                 }
86                 if len(line) >= 5 && string(line[0:5]) == "[...]" {
87                         if receivedBytes == nil {
88                                 t.Fatal("Beginning of line reported as continuation")
89                         }
90                         line = line[5:]
91                 }
92                 if len(line) >= 6 && string(line[len(line)-6:len(line)]) == "[...]\n" {
93                         line = line[:len(line)-6]
94                 } else {
95                         done = true
96                 }
97                 receivedBytes = append(receivedBytes, line...)
98         }
99         if bytes.Compare(receivedBytes, sentBytes) != 0 {
100                 t.Fatalf("sent %d bytes, got %d different bytes", len(sentBytes), len(receivedBytes))
101         }
102
103         if after, err := rcv.ReadBytes('\n'); err != nil || string(after) != "after\n" {
104                 t.Fatal("\"after\n\" not received (got \"%s\", %s)", after, err)
105         }
106
107         select {
108         case <-time.After(time.Second):
109                 t.Fatal("Timeout")
110         case <-control:
111                 // Done.
112         }
113 }
114
115 func captureLogs() *bufio.Reader {
116         // Send childLog to our bufio reader instead of stderr
117         stderrIn, stderrOut := io.Pipe()
118         childLog = log.New(stderrOut, "", 0)
119         statLog = log.New(stderrOut, "crunchstat: ", 0)
120         return bufio.NewReader(stderrIn)
121 }
122
123 func uncaptureLogs() {
124         childLog = log.New(os.Stderr, "", 0)
125         statLog = log.New(os.Stderr, "crunchstat: ", 0)
126 }