...
1 package log
2
3 import (
4 "fmt"
5 "log/syslog"
6 "regexp"
7 "strings"
8 "time"
9 )
10
11
12 func UseMock() *Mock {
13 m := NewMock()
14 _ = Set(m)
15 return m
16 }
17
18
19 func NewMock() *Mock {
20 return &Mock{impl{newMockWriter()}}
21 }
22
23
24
25
26 func NewWaitingMock() *WaitingMock {
27 return &WaitingMock{impl{newWaitingMockWriter()}}
28 }
29
30
31
32 type Mock struct {
33 impl
34 }
35
36
37 type WaitingMock struct {
38 impl
39 }
40
41
42
43
44 type mockWriter struct {
45 logged []string
46 msgChan chan<- string
47 getChan <-chan []string
48 clearChan chan<- struct{}
49 closeChan chan<- struct{}
50 }
51
52 var levelName = map[syslog.Priority]string{
53 syslog.LOG_ERR: "ERR",
54 syslog.LOG_WARNING: "WARNING",
55 syslog.LOG_INFO: "INFO",
56 syslog.LOG_DEBUG: "DEBUG",
57 }
58
59 func (w *mockWriter) logAtLevel(p syslog.Priority, msg string, a ...interface{}) {
60 w.msgChan <- fmt.Sprintf("%s: %s", levelName[p&7], fmt.Sprintf(msg, a...))
61 }
62
63
64 func newMockWriter() *mockWriter {
65 msgChan := make(chan string)
66 getChan := make(chan []string)
67 clearChan := make(chan struct{})
68 closeChan := make(chan struct{})
69 w := &mockWriter{
70 logged: []string{},
71 msgChan: msgChan,
72 getChan: getChan,
73 clearChan: clearChan,
74 closeChan: closeChan,
75 }
76 go func() {
77 for {
78 select {
79 case logMsg := <-msgChan:
80 w.logged = append(w.logged, logMsg)
81 case getChan <- w.logged:
82 case <-clearChan:
83 w.logged = []string{}
84 case <-closeChan:
85 close(getChan)
86 return
87 }
88 }
89 }()
90 return w
91 }
92
93
94
95
96
97 func (m *Mock) GetAll() []string {
98 w := m.w.(*mockWriter)
99 return <-w.getChan
100 }
101
102
103
104
105
106
107
108 func (m *Mock) GetAllMatching(reString string) []string {
109 var matches []string
110 w := m.w.(*mockWriter)
111 re := regexp.MustCompile(reString)
112 for _, logMsg := range <-w.getChan {
113 if re.MatchString(logMsg) {
114 matches = append(matches, logMsg)
115 }
116 }
117 return matches
118 }
119
120 func (m *Mock) ExpectMatch(reString string) error {
121 results := m.GetAllMatching(reString)
122 if len(results) == 0 {
123 return fmt.Errorf("expected log line %q, got %q", reString, strings.Join(m.GetAll(), "\n"))
124 }
125 return nil
126 }
127
128
129 func (m *Mock) Clear() {
130 w := m.w.(*mockWriter)
131 w.clearChan <- struct{}{}
132 }
133
134 type waitingMockWriter struct {
135 logChan chan string
136 }
137
138
139 func newWaitingMockWriter() *waitingMockWriter {
140 logChan := make(chan string, 1000)
141 return &waitingMockWriter{
142 logChan,
143 }
144 }
145
146 func (m *waitingMockWriter) logAtLevel(p syslog.Priority, msg string, a ...interface{}) {
147 m.logChan <- fmt.Sprintf("%s: %s", levelName[p&7], fmt.Sprintf(msg, a...))
148 }
149
150
151
152
153 func (m *WaitingMock) WaitForMatch(reString string, timeout time.Duration) (string, error) {
154 w := m.w.(*waitingMockWriter)
155 deadline := time.After(timeout)
156 re := regexp.MustCompile(reString)
157 for {
158 select {
159 case logLine := <-w.logChan:
160 if re.MatchString(logLine) {
161 close(w.logChan)
162 return logLine, nil
163 }
164 case <-deadline:
165 return "", fmt.Errorf("timeout waiting for match: %q", reString)
166 }
167 }
168 }
169
View as plain text