Merge lp:~pedronis/ubuntu-push/testlog into lp:ubuntu-push
- testlog
- Merge into trunk
Proposed by
Samuele Pedroni
Status: | Merged |
---|---|
Approved by: | Samuele Pedroni |
Approved revision: | 54 |
Merged at revision: | 52 |
Proposed branch: | lp:~pedronis/ubuntu-push/testlog |
Merge into: | lp:ubuntu-push |
Diff against target: |
398 lines (+128/-57) 6 files modified
logger/logger.go (+31/-12) logger/logger_test.go (+10/-0) server/broker/simple/suite_test.go (+3/-3) server/broker/testsuite/suite.go (+12/-9) server/listener/listener_test.go (+13/-14) testing/helpers.go (+59/-19) |
To merge this branch: | bzr merge lp:~pedronis/ubuntu-push/testlog |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
John Lenton (community) | Approve | ||
Review via email:
|
Commit message
base the simple logger only on having a log.Logger-style Output(); given this we can introduce a testing.TestLogger that does redirecting of logs to the gocheck.C object if wired in SetUpTest and also does its own capture
Description of the change
base the simple logger only on having a log.Logger-style Output()
reexport that as we will need it for mgo logging,
given this we can introduce a testing.TestLogger that does redirecting of logs to the gocheck.C object if wired in SetUpTest and also does its own capture.
start using that in the couple of places that were depending on SyncedLogBuffer
To post a comment you must log in.
lp:~pedronis/ubuntu-push/testlog
updated
- 54. By Samuele Pedroni
-
period
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
John Lenton (chipaca) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'logger/logger.go' | |||
2 | --- logger/logger.go 2014-01-16 13:36:32 +0000 | |||
3 | +++ logger/logger.go 2014-02-04 21:37:48 +0000 | |||
4 | @@ -27,6 +27,8 @@ | |||
5 | 27 | 27 | ||
6 | 28 | // Logger is a simple logger interface with logging at levels. | 28 | // Logger is a simple logger interface with logging at levels. |
7 | 29 | type Logger interface { | 29 | type Logger interface { |
8 | 30 | // (Re)xpose base Output for logging events. | ||
9 | 31 | Output(calldept int, s string) error | ||
10 | 30 | // Errorf logs an error. | 32 | // Errorf logs an error. |
11 | 31 | Errorf(format string, v ...interface{}) | 33 | Errorf(format string, v ...interface{}) |
12 | 32 | // Fatalf logs an error and exists the program with os.Exit(1). | 34 | // Fatalf logs an error and exists the program with os.Exit(1). |
13 | @@ -41,8 +43,8 @@ | |||
14 | 41 | } | 43 | } |
15 | 42 | 44 | ||
16 | 43 | type simpleLogger struct { | 45 | type simpleLogger struct { |
19 | 44 | *log.Logger | 46 | outputFunc func(calldepth int, s string) error |
20 | 45 | nlevel int | 47 | nlevel int |
21 | 46 | } | 48 | } |
22 | 47 | 49 | ||
23 | 48 | const ( | 50 | const ( |
24 | @@ -57,24 +59,41 @@ | |||
25 | 57 | "debug": lDebug, | 59 | "debug": lDebug, |
26 | 58 | } | 60 | } |
27 | 59 | 61 | ||
31 | 60 | // NewSimpleLogger creates a logger logging only up to the given level. | 62 | // NewSimpleLoggerFromMinimalLogger creates a logger logging only up |
32 | 61 | // level can be in order: "error", "info", "debug". | 63 | // to the given level. level can be in order: "error", "info", |
33 | 62 | func NewSimpleLogger(w io.Writer, level string) Logger { | 64 | // "debug". It takes a value just implementing stlib Logger.Output(). |
34 | 65 | func NewSimpleLoggerFromMinimalLogger(minLog interface { | ||
35 | 66 | Output(calldepth int, s string) error | ||
36 | 67 | }, level string) Logger { | ||
37 | 63 | nlevel := levelToNLevel[level] | 68 | nlevel := levelToNLevel[level] |
38 | 64 | return &simpleLogger{ | 69 | return &simpleLogger{ |
39 | 70 | minLog.Output, | ||
40 | 71 | nlevel, | ||
41 | 72 | } | ||
42 | 73 | } | ||
43 | 74 | |||
44 | 75 | // NewSimpleLogger creates a logger logging only up to the given | ||
45 | 76 | // level. level can be in order: "error", "info", "debug". It takes a | ||
46 | 77 | // io.Writer. | ||
47 | 78 | func NewSimpleLogger(w io.Writer, level string) Logger { | ||
48 | 79 | return NewSimpleLoggerFromMinimalLogger( | ||
49 | 65 | log.New(w, "", log.Ldate|log.Ltime|log.Lmicroseconds), | 80 | log.New(w, "", log.Ldate|log.Ltime|log.Lmicroseconds), |
52 | 66 | nlevel, | 81 | level, |
53 | 67 | } | 82 | ) |
54 | 83 | } | ||
55 | 84 | |||
56 | 85 | func (lg *simpleLogger) Output(calldepth int, s string) error { | ||
57 | 86 | return lg.outputFunc(calldepth+2, s) | ||
58 | 68 | } | 87 | } |
59 | 69 | 88 | ||
60 | 70 | func (lg *simpleLogger) Errorf(format string, v ...interface{}) { | 89 | func (lg *simpleLogger) Errorf(format string, v ...interface{}) { |
62 | 71 | lg.Printf("ERROR "+format, v...) | 90 | lg.outputFunc(2, fmt.Sprintf("ERROR "+format, v...)) |
63 | 72 | } | 91 | } |
64 | 73 | 92 | ||
65 | 74 | var osExit = os.Exit // for testing | 93 | var osExit = os.Exit // for testing |
66 | 75 | 94 | ||
67 | 76 | func (lg *simpleLogger) Fatalf(format string, v ...interface{}) { | 95 | func (lg *simpleLogger) Fatalf(format string, v ...interface{}) { |
69 | 77 | lg.Printf("ERROR "+format, v...) | 96 | lg.outputFunc(2, fmt.Sprintf("ERROR "+format, v...)) |
70 | 78 | osExit(1) | 97 | osExit(1) |
71 | 79 | } | 98 | } |
72 | 80 | 99 | ||
73 | @@ -83,17 +102,17 @@ | |||
74 | 83 | stack := make([]byte, 8*1024) // Stack writes less but doesn't fail | 102 | stack := make([]byte, 8*1024) // Stack writes less but doesn't fail |
75 | 84 | stackWritten := runtime.Stack(stack, false) | 103 | stackWritten := runtime.Stack(stack, false) |
76 | 85 | stack = stack[:stackWritten] | 104 | stack = stack[:stackWritten] |
78 | 86 | lg.Printf("ERROR(PANIC) %s:\n%s", msg, stack) | 105 | lg.outputFunc(2, fmt.Sprintf("ERROR(PANIC) %s:\n%s", msg, stack)) |
79 | 87 | } | 106 | } |
80 | 88 | 107 | ||
81 | 89 | func (lg *simpleLogger) Infof(format string, v ...interface{}) { | 108 | func (lg *simpleLogger) Infof(format string, v ...interface{}) { |
82 | 90 | if lg.nlevel >= lInfo { | 109 | if lg.nlevel >= lInfo { |
84 | 91 | lg.Printf("INFO "+format, v...) | 110 | lg.outputFunc(2, fmt.Sprintf("INFO "+format, v...)) |
85 | 92 | } | 111 | } |
86 | 93 | } | 112 | } |
87 | 94 | 113 | ||
88 | 95 | func (lg *simpleLogger) Debugf(format string, v ...interface{}) { | 114 | func (lg *simpleLogger) Debugf(format string, v ...interface{}) { |
89 | 96 | if lg.nlevel >= lDebug { | 115 | if lg.nlevel >= lDebug { |
91 | 97 | lg.Printf("DEBUG "+format, v...) | 116 | lg.outputFunc(2, fmt.Sprintf("DEBUG "+format, v...)) |
92 | 98 | } | 117 | } |
93 | 99 | } | 118 | } |
94 | 100 | 119 | ||
95 | === modified file 'logger/logger_test.go' | |||
96 | --- logger/logger_test.go 2014-01-16 13:36:32 +0000 | |||
97 | +++ logger/logger_test.go 2014-02-04 21:37:48 +0000 | |||
98 | @@ -20,6 +20,7 @@ | |||
99 | 20 | "bytes" | 20 | "bytes" |
100 | 21 | "fmt" | 21 | "fmt" |
101 | 22 | . "launchpad.net/gocheck" | 22 | . "launchpad.net/gocheck" |
102 | 23 | "log" | ||
103 | 23 | "os" | 24 | "os" |
104 | 24 | "runtime" | 25 | "runtime" |
105 | 25 | "testing" | 26 | "testing" |
106 | @@ -127,3 +128,12 @@ | |||
107 | 127 | panicAndRecover(logger, 6, false, &line, &ok) | 128 | panicAndRecover(logger, 6, false, &line, &ok) |
108 | 128 | c.Check(buf.String(), Equals, "") | 129 | c.Check(buf.String(), Equals, "") |
109 | 129 | } | 130 | } |
110 | 131 | |||
111 | 132 | func (s *loggerSuite) TestReexposeOutput(c *C) { | ||
112 | 133 | buf := &bytes.Buffer{} | ||
113 | 134 | baselog := log.New(buf, "", log.Lshortfile) | ||
114 | 135 | logger := NewSimpleLoggerFromMinimalLogger(baselog, "error") | ||
115 | 136 | baselog.Output(1, "foobar") | ||
116 | 137 | logger.Output(1, "foobaz") | ||
117 | 138 | c.Check(buf.String(), Matches, "logger_test.go:[0-9]+: foobar\nlogger_test.go:[0-9]+: foobaz\n") | ||
118 | 139 | } | ||
119 | 130 | 140 | ||
120 | === modified file 'server/broker/simple/suite_test.go' | |||
121 | --- server/broker/simple/suite_test.go 2014-02-03 15:13:00 +0000 | |||
122 | +++ server/broker/simple/suite_test.go 2014-02-04 21:37:48 +0000 | |||
123 | @@ -32,13 +32,13 @@ | |||
124 | 32 | } | 32 | } |
125 | 33 | 33 | ||
126 | 34 | var _ = Suite(&commonBrokerSuite{testsuite.CommonBrokerSuite{ | 34 | var _ = Suite(&commonBrokerSuite{testsuite.CommonBrokerSuite{ |
128 | 35 | func(sto store.PendingStore, cfg broker.BrokerConfig, log logger.Logger) testsuite.FullBroker { | 35 | MakeBroker: func(sto store.PendingStore, cfg broker.BrokerConfig, log logger.Logger) testsuite.FullBroker { |
129 | 36 | return NewSimpleBroker(sto, cfg, log) | 36 | return NewSimpleBroker(sto, cfg, log) |
130 | 37 | }, | 37 | }, |
132 | 38 | func(b broker.Broker, deviceId string) broker.BrokerSession { | 38 | RevealSession: func(b broker.Broker, deviceId string) broker.BrokerSession { |
133 | 39 | return b.(*SimpleBroker).registry[deviceId] | 39 | return b.(*SimpleBroker).registry[deviceId] |
134 | 40 | }, | 40 | }, |
136 | 41 | func(exchg broker.Exchange) *broker.BroadcastExchange { | 41 | RevealBroadcastExchange: func(exchg broker.Exchange) *broker.BroadcastExchange { |
137 | 42 | return exchg.(*broker.BroadcastExchange) | 42 | return exchg.(*broker.BroadcastExchange) |
138 | 43 | }, | 43 | }, |
139 | 44 | }}) | 44 | }}) |
140 | 45 | 45 | ||
141 | === modified file 'server/broker/testsuite/suite.go' | |||
142 | --- server/broker/testsuite/suite.go 2014-02-03 15:13:00 +0000 | |||
143 | +++ server/broker/testsuite/suite.go 2014-02-04 21:37:48 +0000 | |||
144 | @@ -48,6 +48,12 @@ | |||
145 | 48 | RevealSession func(broker.Broker, string) broker.BrokerSession | 48 | RevealSession func(broker.Broker, string) broker.BrokerSession |
146 | 49 | // Let us get to a broker.BroadcastExchange from an Exchange. | 49 | // Let us get to a broker.BroadcastExchange from an Exchange. |
147 | 50 | RevealBroadcastExchange func(broker.Exchange) *broker.BroadcastExchange | 50 | RevealBroadcastExchange func(broker.Exchange) *broker.BroadcastExchange |
148 | 51 | // private | ||
149 | 52 | testlog *helpers.TestLogger | ||
150 | 53 | } | ||
151 | 54 | |||
152 | 55 | func (s *CommonBrokerSuite) SetUpTest(c *C) { | ||
153 | 56 | s.testlog = helpers.NewTestLogger(c, "error") | ||
154 | 51 | } | 57 | } |
155 | 52 | 58 | ||
156 | 53 | var testBrokerConfig = &testing.TestBrokerConfig{10, 5} | 59 | var testBrokerConfig = &testing.TestBrokerConfig{10, 5} |
157 | @@ -110,16 +116,14 @@ | |||
158 | 110 | } | 116 | } |
159 | 111 | 117 | ||
160 | 112 | func (s *CommonBrokerSuite) TestRegistrationFeedPendingError(c *C) { | 118 | func (s *CommonBrokerSuite) TestRegistrationFeedPendingError(c *C) { |
161 | 113 | buf := &helpers.SyncedLogBuffer{} | ||
162 | 114 | logger := logger.NewSimpleLogger(buf, "error") | ||
163 | 115 | sto := &testFailingStore{} | 119 | sto := &testFailingStore{} |
165 | 116 | b := s.MakeBroker(sto, testBrokerConfig, logger) | 120 | b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
166 | 117 | b.Start() | 121 | b.Start() |
167 | 118 | defer b.Stop() | 122 | defer b.Stop() |
168 | 119 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 123 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) |
169 | 120 | c.Assert(err, IsNil) | 124 | c.Assert(err, IsNil) |
170 | 121 | // but | 125 | // but |
172 | 122 | c.Check(buf.String(), Matches, ".*ERROR unsuccessful feed pending, get channel snapshot for 0: get channel snapshot fail\n") | 126 | c.Check(s.testlog.Captured(), Matches, "ERROR unsuccessful feed pending, get channel snapshot for 0: get channel snapshot fail\n") |
173 | 123 | } | 127 | } |
174 | 124 | 128 | ||
175 | 125 | func (s *CommonBrokerSuite) TestRegistrationLastWins(c *C) { | 129 | func (s *CommonBrokerSuite) TestRegistrationLastWins(c *C) { |
176 | @@ -188,10 +192,9 @@ | |||
177 | 188 | } | 192 | } |
178 | 189 | 193 | ||
179 | 190 | func (s *CommonBrokerSuite) TestBroadcastFail(c *C) { | 194 | func (s *CommonBrokerSuite) TestBroadcastFail(c *C) { |
182 | 191 | buf := &helpers.SyncedLogBuffer{Written: make(chan bool, 1)} | 195 | s.testlog.Written = make(chan bool, 1) |
181 | 192 | logger := logger.NewSimpleLogger(buf, "error") | ||
183 | 193 | sto := &testFailingStore{countdownToFail: 1} | 196 | sto := &testFailingStore{countdownToFail: 1} |
185 | 194 | b := s.MakeBroker(sto, testBrokerConfig, logger) | 197 | b := s.MakeBroker(sto, testBrokerConfig, s.testlog) |
186 | 195 | b.Start() | 198 | b.Start() |
187 | 196 | defer b.Stop() | 199 | defer b.Stop() |
188 | 197 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) | 200 | _, err := b.Register(&protocol.ConnectMsg{Type: "connect", DeviceId: "dev-1"}) |
189 | @@ -200,7 +203,7 @@ | |||
190 | 200 | select { | 203 | select { |
191 | 201 | case <-time.After(5 * time.Second): | 204 | case <-time.After(5 * time.Second): |
192 | 202 | c.Fatal("taking too long to log error") | 205 | c.Fatal("taking too long to log error") |
194 | 203 | case <-buf.Written: | 206 | case <-s.testlog.Written: |
195 | 204 | } | 207 | } |
197 | 205 | c.Check(buf.String(), Matches, ".*ERROR unsuccessful broadcast, get channel snapshot for 0: get channel snapshot fail\n") | 208 | c.Check(s.testlog.Captured(), Matches, "ERROR unsuccessful broadcast, get channel snapshot for 0: get channel snapshot fail\n") |
198 | 206 | } | 209 | } |
199 | 207 | 210 | ||
200 | === modified file 'server/listener/listener_test.go' | |||
201 | --- server/listener/listener_test.go 2014-01-21 21:36:07 +0000 | |||
202 | +++ server/listener/listener_test.go 2014-02-04 21:37:48 +0000 | |||
203 | @@ -20,7 +20,6 @@ | |||
204 | 20 | "crypto/tls" | 20 | "crypto/tls" |
205 | 21 | "crypto/x509" | 21 | "crypto/x509" |
206 | 22 | . "launchpad.net/gocheck" | 22 | . "launchpad.net/gocheck" |
207 | 23 | "launchpad.net/ubuntu-push/logger" | ||
208 | 24 | helpers "launchpad.net/ubuntu-push/testing" | 23 | helpers "launchpad.net/ubuntu-push/testing" |
209 | 25 | "net" | 24 | "net" |
210 | 26 | "syscall" | 25 | "syscall" |
211 | @@ -30,7 +29,9 @@ | |||
212 | 30 | 29 | ||
213 | 31 | func TestListener(t *testing.T) { TestingT(t) } | 30 | func TestListener(t *testing.T) { TestingT(t) } |
214 | 32 | 31 | ||
216 | 33 | type listenerSuite struct{} | 32 | type listenerSuite struct { |
217 | 33 | testlog *helpers.TestLogger | ||
218 | 34 | } | ||
219 | 34 | 35 | ||
220 | 35 | var _ = Suite(&listenerSuite{}) | 36 | var _ = Suite(&listenerSuite{}) |
221 | 36 | 37 | ||
222 | @@ -50,6 +51,10 @@ | |||
223 | 50 | } | 51 | } |
224 | 51 | } | 52 | } |
225 | 52 | 53 | ||
226 | 54 | func (s *listenerSuite) SetUpTest(c *C) { | ||
227 | 55 | s.testlog = helpers.NewTestLogger(c, "error") | ||
228 | 56 | } | ||
229 | 57 | |||
230 | 53 | type testDevListenerCfg struct { | 58 | type testDevListenerCfg struct { |
231 | 54 | addr string | 59 | addr string |
232 | 55 | } | 60 | } |
233 | @@ -135,14 +140,12 @@ | |||
234 | 135 | } | 140 | } |
235 | 136 | 141 | ||
236 | 137 | func (s *listenerSuite) TestDeviceAcceptLoop(c *C) { | 142 | func (s *listenerSuite) TestDeviceAcceptLoop(c *C) { |
237 | 138 | buf := &helpers.SyncedLogBuffer{} | ||
238 | 139 | logger := logger.NewSimpleLogger(buf, "error") | ||
239 | 140 | lst, err := DeviceListen(&testDevListenerCfg{"127.0.0.1:0"}) | 143 | lst, err := DeviceListen(&testDevListenerCfg{"127.0.0.1:0"}) |
240 | 141 | c.Check(err, IsNil) | 144 | c.Check(err, IsNil) |
241 | 142 | defer lst.Close() | 145 | defer lst.Close() |
242 | 143 | errCh := make(chan error) | 146 | errCh := make(chan error) |
243 | 144 | go func() { | 147 | go func() { |
245 | 145 | errCh <- lst.AcceptLoop(testSession, logger) | 148 | errCh <- lst.AcceptLoop(testSession, s.testlog) |
246 | 146 | }() | 149 | }() |
247 | 147 | listenerAddr := lst.Addr().String() | 150 | listenerAddr := lst.Addr().String() |
248 | 148 | conn1, err := testTlsDial(c, listenerAddr) | 151 | conn1, err := testTlsDial(c, listenerAddr) |
249 | @@ -157,12 +160,10 @@ | |||
250 | 157 | testReadByte(c, conn2, '2') | 160 | testReadByte(c, conn2, '2') |
251 | 158 | lst.Close() | 161 | lst.Close() |
252 | 159 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") | 162 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") |
254 | 160 | c.Check(buf.String(), Equals, "") | 163 | c.Check(s.testlog.Captured(), Equals, "") |
255 | 161 | } | 164 | } |
256 | 162 | 165 | ||
257 | 163 | func (s *listenerSuite) TestDeviceAcceptLoopTemporaryError(c *C) { | 166 | func (s *listenerSuite) TestDeviceAcceptLoopTemporaryError(c *C) { |
258 | 164 | buf := &helpers.SyncedLogBuffer{} | ||
259 | 165 | logger := logger.NewSimpleLogger(buf, "error") | ||
260 | 166 | // ENFILE is not the temp network error we want to handle this way | 167 | // ENFILE is not the temp network error we want to handle this way |
261 | 167 | // but is relatively easy to generate in a controlled way | 168 | // but is relatively easy to generate in a controlled way |
262 | 168 | var err error | 169 | var err error |
263 | @@ -171,7 +172,7 @@ | |||
264 | 171 | defer lst.Close() | 172 | defer lst.Close() |
265 | 172 | errCh := make(chan error) | 173 | errCh := make(chan error) |
266 | 173 | go func() { | 174 | go func() { |
268 | 174 | errCh <- lst.AcceptLoop(testSession, logger) | 175 | errCh <- lst.AcceptLoop(testSession, s.testlog) |
269 | 175 | }() | 176 | }() |
270 | 176 | listenerAddr := lst.Addr().String() | 177 | listenerAddr := lst.Addr().String() |
271 | 177 | conns := make([]net.Conn, 0, NofileMax) | 178 | conns := make([]net.Conn, 0, NofileMax) |
272 | @@ -195,12 +196,10 @@ | |||
273 | 195 | testReadByte(c, conn2, '2') | 196 | testReadByte(c, conn2, '2') |
274 | 196 | lst.Close() | 197 | lst.Close() |
275 | 197 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") | 198 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") |
277 | 198 | c.Check(buf.String(), Matches, ".*device listener:.*accept.*too many open.*-- retrying\n") | 199 | c.Check(s.testlog.Captured(), Matches, ".*device listener:.*accept.*too many open.*-- retrying\n") |
278 | 199 | } | 200 | } |
279 | 200 | 201 | ||
280 | 201 | func (s *listenerSuite) TestDeviceAcceptLoopPanic(c *C) { | 202 | func (s *listenerSuite) TestDeviceAcceptLoopPanic(c *C) { |
281 | 202 | buf := &helpers.SyncedLogBuffer{} | ||
282 | 203 | logger := logger.NewSimpleLogger(buf, "error") | ||
283 | 204 | lst, err := DeviceListen(&testDevListenerCfg{"127.0.0.1:0"}) | 203 | lst, err := DeviceListen(&testDevListenerCfg{"127.0.0.1:0"}) |
284 | 205 | c.Check(err, IsNil) | 204 | c.Check(err, IsNil) |
285 | 206 | defer lst.Close() | 205 | defer lst.Close() |
286 | @@ -209,12 +208,12 @@ | |||
287 | 209 | errCh <- lst.AcceptLoop(func(conn net.Conn) error { | 208 | errCh <- lst.AcceptLoop(func(conn net.Conn) error { |
288 | 210 | defer conn.Close() | 209 | defer conn.Close() |
289 | 211 | panic("session crash") | 210 | panic("session crash") |
291 | 212 | }, logger) | 211 | }, s.testlog) |
292 | 213 | }() | 212 | }() |
293 | 214 | listenerAddr := lst.Addr().String() | 213 | listenerAddr := lst.Addr().String() |
294 | 215 | _, err = testTlsDial(c, listenerAddr) | 214 | _, err = testTlsDial(c, listenerAddr) |
295 | 216 | c.Assert(err, Not(IsNil)) | 215 | c.Assert(err, Not(IsNil)) |
296 | 217 | lst.Close() | 216 | lst.Close() |
297 | 218 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") | 217 | c.Check(<-errCh, ErrorMatches, ".*use of closed.*") |
299 | 219 | c.Check(buf.String(), Matches, "(?s).* ERROR\\(PANIC\\) terminating device connection on: session crash:.*AcceptLoop.*") | 218 | c.Check(s.testlog.Captured(), Matches, "(?s)ERROR\\(PANIC\\) terminating device connection on: session crash:.*AcceptLoop.*") |
300 | 220 | } | 219 | } |
301 | 221 | 220 | ||
302 | === modified file 'testing/helpers.go' | |||
303 | --- testing/helpers.go 2014-01-21 21:36:07 +0000 | |||
304 | +++ testing/helpers.go 2014-02-04 21:37:48 +0000 | |||
305 | @@ -18,34 +18,74 @@ | |||
306 | 18 | package testing | 18 | package testing |
307 | 19 | 19 | ||
308 | 20 | import ( | 20 | import ( |
310 | 21 | "bytes" | 21 | "launchpad.net/ubuntu-push/logger" |
311 | 22 | "path/filepath" | 22 | "path/filepath" |
312 | 23 | "runtime" | 23 | "runtime" |
313 | 24 | "strings" | ||
314 | 24 | "sync" | 25 | "sync" |
315 | 25 | ) | 26 | ) |
316 | 26 | 27 | ||
322 | 27 | // SyncedLogBuffer can be used with NewSimpleLogger avoiding races | 28 | type captureHelper struct { |
323 | 28 | // when checking the logging done from different goroutines. | 29 | outputFunc func(int, string) error |
324 | 29 | type SyncedLogBuffer struct { | 30 | lock sync.Mutex |
325 | 30 | bytes.Buffer | 31 | logEvents []string |
326 | 31 | lock sync.Mutex | 32 | written *chan bool |
327 | 33 | } | ||
328 | 34 | |||
329 | 35 | func (h *captureHelper) Output(calldepth int, s string) error { | ||
330 | 36 | err := h.outputFunc(calldepth+2, s) | ||
331 | 37 | if err == nil { | ||
332 | 38 | h.lock.Lock() | ||
333 | 39 | defer h.lock.Unlock() | ||
334 | 40 | if *h.written != nil { | ||
335 | 41 | *h.written <- true | ||
336 | 42 | } | ||
337 | 43 | h.logEvents = append(h.logEvents, s+"\n") | ||
338 | 44 | } | ||
339 | 45 | return err | ||
340 | 46 | } | ||
341 | 47 | |||
342 | 48 | func (h *captureHelper) captured() string { | ||
343 | 49 | h.lock.Lock() | ||
344 | 50 | defer h.lock.Unlock() | ||
345 | 51 | return strings.Join(h.logEvents, "") | ||
346 | 52 | } | ||
347 | 53 | |||
348 | 54 | func (h *captureHelper) reset() { | ||
349 | 55 | h.lock.Lock() | ||
350 | 56 | defer h.lock.Unlock() | ||
351 | 57 | h.logEvents = nil | ||
352 | 58 | } | ||
353 | 59 | |||
354 | 60 | // TestLogger implements logger.Logger using gocheck.C and supporting | ||
355 | 61 | // capturing log strings. | ||
356 | 62 | type TestLogger struct { | ||
357 | 63 | logger.Logger | ||
358 | 64 | helper *captureHelper | ||
359 | 32 | Written chan bool | 65 | Written chan bool |
360 | 33 | } | 66 | } |
361 | 34 | 67 | ||
368 | 35 | func (buf *SyncedLogBuffer) Write(b []byte) (int, error) { | 68 | // NewTestLogger can be used in tests instead of NewSimpleLogger(FromMinimalLogger). |
369 | 36 | buf.lock.Lock() | 69 | func NewTestLogger(minLog interface { |
370 | 37 | defer buf.lock.Unlock() | 70 | Output(int, string) error |
371 | 38 | n, err := buf.Buffer.Write(b) | 71 | }, level string) *TestLogger { |
372 | 39 | if buf.Written != nil { | 72 | h := &captureHelper{outputFunc: minLog.Output} |
373 | 40 | buf.Written <- true | 73 | log := &TestLogger{ |
374 | 74 | Logger: logger.NewSimpleLoggerFromMinimalLogger(h, level), | ||
375 | 75 | helper: h, | ||
376 | 41 | } | 76 | } |
384 | 42 | return n, err | 77 | h.written = &log.Written |
385 | 43 | } | 78 | return log |
386 | 44 | 79 | } | |
387 | 45 | func (buf *SyncedLogBuffer) String() string { | 80 | |
388 | 46 | buf.lock.Lock() | 81 | // Captured returns accumulated log events. |
389 | 47 | defer buf.lock.Unlock() | 82 | func (tlog *TestLogger) Captured() string { |
390 | 48 | return buf.Buffer.String() | 83 | return tlog.helper.captured() |
391 | 84 | } | ||
392 | 85 | |||
393 | 86 | // Reset resets accumulated log events. | ||
394 | 87 | func (tlog *TestLogger) ResetCapture() { | ||
395 | 88 | tlog.helper.reset() | ||
396 | 49 | } | 89 | } |
397 | 50 | 90 | ||
398 | 51 | // SourceRelative produces a path relative to the source code, makes | 91 | // SourceRelative produces a path relative to the source code, makes |