github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/logforwarder/logforwarder_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package logforwarder_test 5 6 import ( 7 "time" 8 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 "github.com/juju/testing" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 "gopkg.in/juju/worker.v1/workertest" 15 16 "github.com/juju/juju/api/base" 17 "github.com/juju/juju/apiserver/params" 18 "github.com/juju/juju/core/watcher" 19 "github.com/juju/juju/logfwd" 20 "github.com/juju/juju/logfwd/syslog" 21 coretesting "github.com/juju/juju/testing" 22 "github.com/juju/juju/version" 23 "github.com/juju/juju/worker/logforwarder" 24 ) 25 26 type LogForwarderSuite struct { 27 testing.IsolationSuite 28 29 stream *stubStream 30 sender *stubSender 31 rec logfwd.Record 32 } 33 34 var _ = gc.Suite(&LogForwarderSuite{}) 35 36 func (s *LogForwarderSuite) SetUpTest(c *gc.C) { 37 s.IsolationSuite.SetUpTest(c) 38 39 s.stream = newStubStream() 40 s.sender = newStubSender() 41 s.rec = logfwd.Record{ 42 Origin: logfwd.Origin{ 43 ControllerUUID: "feebdaed-2f18-4fd2-967d-db9663db7bea", 44 ModelUUID: "deadbeef-2f18-4fd2-967d-db9663db7bea", 45 Hostname: "machine-99.deadbeef-2f18-4fd2-967d-db9663db7bea", 46 Type: logfwd.OriginTypeMachine, 47 Name: "99", 48 Software: logfwd.Software{ 49 PrivateEnterpriseNumber: 28978, 50 Name: "jujud-machine-agent", 51 Version: version.Current, 52 }, 53 }, 54 ID: 10, 55 Timestamp: time.Now(), 56 Level: loggo.INFO, 57 Location: logfwd.SourceLocation{ 58 Module: "api.logstream.test", 59 Filename: "test.go", 60 Line: 42, 61 }, 62 Message: "send to 10.0.0.1", 63 } 64 } 65 66 func (s *LogForwarderSuite) newLogForwarderArgs( 67 c *gc.C, 68 stream logforwarder.LogStream, 69 sender *stubSender, 70 ) logforwarder.OpenLogForwarderArgs { 71 api := &mockLogForwardConfig{ 72 enabled: stream != nil, 73 host: "10.0.0.1", 74 } 75 return s.newLogForwarderArgsWithAPI(c, api, stream, sender) 76 } 77 78 func (s *LogForwarderSuite) newLogForwarderArgsWithAPI( 79 c *gc.C, 80 configAPI logforwarder.LogForwardConfig, 81 stream logforwarder.LogStream, 82 sender *stubSender, 83 ) logforwarder.OpenLogForwarderArgs { 84 return logforwarder.OpenLogForwarderArgs{ 85 Caller: &mockCaller{}, 86 LogForwardConfig: configAPI, 87 ControllerUUID: "feebdaed-2f18-4fd2-967d-db9663db7bea", 88 OpenSink: func(cfg *syslog.RawConfig) (*logforwarder.LogSink, error) { 89 sender.host = cfg.Host 90 sink := &logforwarder.LogSink{ 91 sender, 92 } 93 return sink, nil 94 }, 95 OpenLogStream: func(_ base.APICaller, _ params.LogStreamConfig, controllerUUID string) (logforwarder.LogStream, error) { 96 c.Assert(controllerUUID, gc.Equals, "feebdaed-2f18-4fd2-967d-db9663db7bea") 97 return stream, nil 98 }, 99 } 100 } 101 102 func (s *LogForwarderSuite) TestOne(c *gc.C) { 103 s.stream.addRecords(c, s.rec) 104 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender)) 105 c.Assert(err, jc.ErrorIsNil) 106 defer workertest.DirtyKill(c, lf) 107 108 s.sender.waitForSend(c) 109 workertest.CleanKill(c, lf) 110 s.sender.stub.CheckCalls(c, []testing.StubCall{ 111 {"Send", []interface{}{[]logfwd.Record{s.rec}}}, 112 {"Close", nil}, 113 }) 114 } 115 116 func (s *LogForwarderSuite) TestConfigChange(c *gc.C) { 117 rec0 := s.rec 118 rec1 := s.rec 119 rec1.ID = 11 120 121 api := &mockLogForwardConfig{ 122 enabled: true, 123 host: "10.0.0.1", 124 } 125 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgsWithAPI(c, api, s.stream, s.sender)) 126 c.Assert(err, jc.ErrorIsNil) 127 defer workertest.DirtyKill(c, lf) 128 129 // Send the first record. 130 s.stream.addRecords(c, rec0) 131 s.sender.waitForSend(c) 132 133 // Config change. 134 api.host = "10.0.0.2" 135 api.changes <- struct{}{} 136 s.sender.waitForClose(c) 137 138 // Send the second record. 139 s.stream.addRecords(c, rec1) 140 s.sender.waitForSend(c) 141 142 workertest.CleanKill(c, lf) 143 144 // Check that both records were sent with the config change 145 // applied for the second send. 146 rec1.Message = "send to 10.0.0.2" 147 s.sender.stub.CheckCalls(c, []testing.StubCall{ 148 {"Send", []interface{}{[]logfwd.Record{rec0}}}, 149 {"Close", nil}, 150 {"Send", []interface{}{[]logfwd.Record{rec1}}}, 151 {"Close", nil}, 152 }) 153 } 154 155 func (s *LogForwarderSuite) TestNotEnabled(c *gc.C) { 156 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, nil, s.sender)) 157 c.Assert(err, jc.ErrorIsNil) 158 159 time.Sleep(coretesting.ShortWait) 160 workertest.CleanKill(c, lf) 161 162 // There should be no stream or sender activity when log 163 // forwarding is disabled. 164 s.stream.stub.CheckCallNames(c) 165 s.sender.stub.CheckCallNames(c) 166 } 167 168 func (s *LogForwarderSuite) TestStreamError(c *gc.C) { 169 failure := errors.New("<failure>") 170 s.stream.stub.SetErrors(nil, failure) 171 s.stream.addRecords(c, s.rec) 172 173 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender)) 174 c.Assert(err, jc.ErrorIsNil) 175 defer workertest.DirtyKill(c, lf) 176 177 err = workertest.CheckKilled(c, lf) 178 c.Check(errors.Cause(err), gc.Equals, failure) 179 180 s.sender.stub.CheckCalls(c, []testing.StubCall{ 181 {"Send", []interface{}{[]logfwd.Record{s.rec}}}, 182 {"Close", nil}, 183 }) 184 } 185 186 func (s *LogForwarderSuite) TestSenderError(c *gc.C) { 187 failure := errors.New("<failure>") 188 s.sender.stub.SetErrors(nil, failure) 189 190 rec0 := s.rec 191 rec1 := s.rec 192 rec1.ID = 11 193 s.stream.addRecords(c, rec0, rec1) 194 195 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender)) 196 c.Assert(err, jc.ErrorIsNil) 197 defer workertest.DirtyKill(c, lf) 198 199 err = workertest.CheckKilled(c, lf) 200 c.Check(errors.Cause(err), gc.Equals, failure) 201 202 s.sender.stub.CheckCalls(c, []testing.StubCall{ 203 {"Send", []interface{}{[]logfwd.Record{rec0}}}, 204 {"Send", []interface{}{[]logfwd.Record{rec1}}}, 205 {"Close", nil}, 206 }) 207 } 208 209 type mockLogForwardConfig struct { 210 enabled bool 211 host string 212 changes chan struct{} 213 } 214 215 type mockWatcher struct { 216 watcher.NotifyWatcher 217 changes chan struct{} 218 } 219 220 func (m *mockWatcher) Changes() watcher.NotifyChannel { 221 return m.changes 222 } 223 224 func (*mockWatcher) Kill() { 225 } 226 227 func (*mockWatcher) Wait() error { 228 return nil 229 } 230 231 type mockCaller struct { 232 base.APICaller 233 } 234 235 func (*mockCaller) APICall(objType string, version int, id, request string, params, response interface{}) error { 236 return nil 237 } 238 239 func (*mockCaller) BestFacadeVersion(facade string) int { 240 return 0 241 } 242 243 func (c *mockLogForwardConfig) WatchForLogForwardConfigChanges() (watcher.NotifyWatcher, error) { 244 c.changes = make(chan struct{}, 1) 245 c.changes <- struct{}{} 246 return &mockWatcher{ 247 changes: c.changes, 248 }, nil 249 } 250 251 func (c *mockLogForwardConfig) LogForwardConfig() (*syslog.RawConfig, bool, error) { 252 return &syslog.RawConfig{ 253 Enabled: c.enabled, 254 Host: c.host, 255 CACert: coretesting.CACert, 256 ClientCert: coretesting.ServerCert, 257 ClientKey: coretesting.ServerKey, 258 }, true, nil 259 } 260 261 type stubStream struct { 262 stub *testing.Stub 263 nextRecs chan logfwd.Record 264 } 265 266 func newStubStream() *stubStream { 267 return &stubStream{ 268 stub: new(testing.Stub), 269 nextRecs: make(chan logfwd.Record, 16), 270 } 271 } 272 273 func (s *stubStream) addRecords(c *gc.C, recs ...logfwd.Record) { 274 for _, rec := range recs { 275 s.nextRecs <- rec 276 } 277 } 278 279 func (s *stubStream) Next() ([]logfwd.Record, error) { 280 s.stub.AddCall("Next") 281 if err := s.stub.NextErr(); err != nil { 282 return []logfwd.Record{}, errors.Trace(err) 283 } 284 return []logfwd.Record{<-s.nextRecs}, nil 285 } 286 287 type stubSender struct { 288 stub *testing.Stub 289 activity chan string 290 host string 291 } 292 293 func newStubSender() *stubSender { 294 return &stubSender{ 295 stub: new(testing.Stub), 296 activity: make(chan string, 16), 297 } 298 } 299 300 func (s *stubSender) Send(records []logfwd.Record) error { 301 for i, rec := range records { 302 rec.Message = "send to " + s.host 303 records[i] = rec 304 } 305 s.stub.AddCall("Send", records) 306 s.activity <- "Send" 307 return errors.Trace(s.stub.NextErr()) 308 } 309 310 func (s *stubSender) Close() error { 311 s.stub.AddCall("Close") 312 s.activity <- "Close" 313 return errors.Trace(s.stub.NextErr()) 314 } 315 316 func (s *stubSender) waitForSend(c *gc.C) { 317 s.waitForActivity(c, "Send") 318 } 319 320 func (s *stubSender) waitForClose(c *gc.C) { 321 s.waitForActivity(c, "Close") 322 } 323 324 func (s *stubSender) waitForActivity(c *gc.C, name string) { 325 select { 326 case a := <-s.activity: 327 if a != name { 328 c.Fatalf("expected %v, got %v", name, a) 329 } 330 case <-time.After(coretesting.LongWait): 331 c.Fatalf("timeout out waiting for %v", name) 332 } 333 }