github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/apiserver/debuglog_db_internal_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apiserver 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/juju/loggo" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/state" 15 coretesting "github.com/juju/juju/testing" 16 ) 17 18 type debugLogDBIntSuite struct { 19 coretesting.BaseSuite 20 sock *fakeDebugLogSocket 21 } 22 23 var _ = gc.Suite(&debugLogDBIntSuite{}) 24 25 func (s *debugLogDBIntSuite) SetUpTest(c *gc.C) { 26 s.BaseSuite.SetUpTest(c) 27 s.sock = newFakeDebugLogSocket() 28 } 29 30 func (s *debugLogDBIntSuite) TestParamConversion(c *gc.C) { 31 reqParams := &debugLogParams{ 32 fromTheStart: false, 33 noTail: true, 34 backlog: 11, 35 filterLevel: loggo.INFO, 36 includeEntity: []string{"foo"}, 37 includeModule: []string{"bar"}, 38 excludeEntity: []string{"baz"}, 39 excludeModule: []string{"qux"}, 40 } 41 42 called := false 43 s.PatchValue(&newLogTailer, func(_ state.LoggingState, params *state.LogTailerParams) (state.LogTailer, error) { 44 called = true 45 46 // Start time will be used once the client is extended to send 47 // time range arguments. 48 c.Assert(params.StartTime.IsZero(), jc.IsTrue) 49 c.Assert(params.NoTail, jc.IsTrue) 50 c.Assert(params.MinLevel, gc.Equals, loggo.INFO) 51 c.Assert(params.InitialLines, gc.Equals, 11) 52 c.Assert(params.IncludeEntity, jc.DeepEquals, []string{"foo"}) 53 c.Assert(params.IncludeModule, jc.DeepEquals, []string{"bar"}) 54 c.Assert(params.ExcludeEntity, jc.DeepEquals, []string{"baz"}) 55 c.Assert(params.ExcludeModule, jc.DeepEquals, []string{"qux"}) 56 57 return newFakeLogTailer(), nil 58 }) 59 60 stop := make(chan struct{}) 61 close(stop) // Stop the request immediately. 62 err := handleDebugLogDBRequest(nil, reqParams, s.sock, stop) 63 c.Assert(err, jc.ErrorIsNil) 64 c.Assert(called, jc.IsTrue) 65 } 66 67 func (s *debugLogDBIntSuite) TestParamConversionReplay(c *gc.C) { 68 reqParams := &debugLogParams{ 69 fromTheStart: true, 70 backlog: 123, 71 } 72 73 called := false 74 s.PatchValue(&newLogTailer, func(_ state.LoggingState, params *state.LogTailerParams) (state.LogTailer, error) { 75 called = true 76 77 c.Assert(params.StartTime.IsZero(), jc.IsTrue) 78 c.Assert(params.InitialLines, gc.Equals, 0) 79 80 return newFakeLogTailer(), nil 81 }) 82 83 stop := make(chan struct{}) 84 close(stop) // Stop the request immediately. 85 err := handleDebugLogDBRequest(nil, reqParams, s.sock, stop) 86 c.Assert(err, jc.ErrorIsNil) 87 c.Assert(called, jc.IsTrue) 88 } 89 90 func (s *debugLogDBIntSuite) TestFullRequest(c *gc.C) { 91 // Set up a fake log tailer with a 2 log records ready to send. 92 tailer := newFakeLogTailer() 93 tailer.logsCh <- &state.LogRecord{ 94 Time: time.Date(2015, 6, 19, 15, 34, 37, 0, time.UTC), 95 Entity: "machine-99", 96 Module: "some.where", 97 Location: "code.go:42", 98 Level: loggo.INFO, 99 Message: "stuff happened", 100 } 101 tailer.logsCh <- &state.LogRecord{ 102 Time: time.Date(2015, 6, 19, 15, 36, 40, 0, time.UTC), 103 Entity: "unit-foo-2", 104 Module: "else.where", 105 Location: "go.go:22", 106 Level: loggo.ERROR, 107 Message: "whoops", 108 } 109 s.PatchValue(&newLogTailer, func(_ state.LoggingState, params *state.LogTailerParams) (state.LogTailer, error) { 110 return tailer, nil 111 }) 112 113 stop := make(chan struct{}) 114 done := s.runRequest(&debugLogParams{}, stop) 115 116 s.assertOutput(c, []string{ 117 "ok", // sendOk() call needs to happen first. 118 "machine-99: 2015-06-19 15:34:37 INFO some.where code.go:42 stuff happened\n", 119 "unit-foo-2: 2015-06-19 15:36:40 ERROR else.where go.go:22 whoops\n", 120 }) 121 122 // Check the request stops when requested. 123 close(stop) 124 s.assertStops(c, done, tailer) 125 } 126 127 func (s *debugLogDBIntSuite) TestRequestStopsWhenTailerStops(c *gc.C) { 128 tailer := newFakeLogTailer() 129 s.PatchValue(&newLogTailer, func(_ state.LoggingState, params *state.LogTailerParams) (state.LogTailer, error) { 130 close(tailer.logsCh) // make the request stop immediately 131 return tailer, nil 132 }) 133 134 err := handleDebugLogDBRequest(nil, &debugLogParams{}, s.sock, nil) 135 c.Assert(err, jc.ErrorIsNil) 136 c.Assert(tailer.stopped, jc.IsTrue) 137 } 138 139 func (s *debugLogDBIntSuite) TestMaxLines(c *gc.C) { 140 // Set up a fake log tailer with a 5 log records ready to send. 141 tailer := newFakeLogTailer() 142 for i := 0; i < 5; i++ { 143 tailer.logsCh <- &state.LogRecord{ 144 Time: time.Date(2015, 6, 19, 15, 34, 37, 0, time.UTC), 145 Entity: "machine-99", 146 Module: "some.where", 147 Location: "code.go:42", 148 Level: loggo.INFO, 149 Message: "stuff happened", 150 } 151 } 152 s.PatchValue(&newLogTailer, func(_ state.LoggingState, params *state.LogTailerParams) (state.LogTailer, error) { 153 return tailer, nil 154 }) 155 156 done := s.runRequest(&debugLogParams{maxLines: 3}, nil) 157 158 s.assertOutput(c, []string{ 159 "ok", // sendOk() call needs to happen first. 160 "machine-99: 2015-06-19 15:34:37 INFO some.where code.go:42 stuff happened\n", 161 "machine-99: 2015-06-19 15:34:37 INFO some.where code.go:42 stuff happened\n", 162 "machine-99: 2015-06-19 15:34:37 INFO some.where code.go:42 stuff happened\n", 163 }) 164 165 // The tailer should now stop by itself after the line limit was reached. 166 s.assertStops(c, done, tailer) 167 } 168 169 func (s *debugLogDBIntSuite) runRequest(params *debugLogParams, stop chan struct{}) chan error { 170 done := make(chan error) 171 go func() { 172 done <- handleDebugLogDBRequest(&fakeState{}, params, s.sock, stop) 173 }() 174 return done 175 } 176 177 func (s *debugLogDBIntSuite) assertOutput(c *gc.C, expectedWrites []string) { 178 timeout := time.After(coretesting.LongWait) 179 for i, expectedWrite := range expectedWrites { 180 select { 181 case actualWrite := <-s.sock.writes: 182 c.Assert(actualWrite, gc.Equals, expectedWrite) 183 case <-timeout: 184 c.Fatalf("timed out waiting for socket write (received %d)", i) 185 } 186 } 187 } 188 189 func (s *debugLogDBIntSuite) assertStops(c *gc.C, done chan error, tailer *fakeLogTailer) { 190 select { 191 case err := <-done: 192 c.Assert(err, jc.ErrorIsNil) 193 c.Assert(tailer.stopped, jc.IsTrue) 194 case <-time.After(coretesting.LongWait): 195 c.Fatal("timed out waiting for request handler to stop") 196 } 197 } 198 199 type fakeState struct { 200 state.LoggingState 201 } 202 203 func newFakeLogTailer() *fakeLogTailer { 204 return &fakeLogTailer{ 205 logsCh: make(chan *state.LogRecord, 10), 206 } 207 } 208 209 type fakeLogTailer struct { 210 state.LogTailer 211 logsCh chan *state.LogRecord 212 stopped bool 213 } 214 215 func (t *fakeLogTailer) Logs() <-chan *state.LogRecord { 216 return t.logsCh 217 } 218 219 func (t *fakeLogTailer) Stop() error { 220 t.stopped = true 221 return nil 222 } 223 224 func (t *fakeLogTailer) Err() error { 225 return nil 226 } 227 228 func newFakeDebugLogSocket() *fakeDebugLogSocket { 229 return &fakeDebugLogSocket{ 230 writes: make(chan string, 10), 231 } 232 } 233 234 type fakeDebugLogSocket struct { 235 writes chan string 236 } 237 238 func (s *fakeDebugLogSocket) sendOk() { 239 s.writes <- "ok" 240 } 241 242 func (s *fakeDebugLogSocket) sendError(err error) { 243 s.writes <- fmt.Sprintf("err: %v", err) 244 } 245 246 func (s *fakeDebugLogSocket) Write(buf []byte) (int, error) { 247 s.writes <- string(buf) 248 return len(buf), nil 249 }