github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/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 "github.com/juju/worker/v3/workertest" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/api/base" 17 "github.com/juju/juju/core/watcher" 18 "github.com/juju/juju/logfwd" 19 "github.com/juju/juju/logfwd/syslog" 20 "github.com/juju/juju/rpc/params" 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 Logger: loggo.GetLogger("test"), 100 } 101 } 102 103 func (s *LogForwarderSuite) TestOne(c *gc.C) { 104 s.stream.addRecords(c, s.rec) 105 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender)) 106 c.Assert(err, jc.ErrorIsNil) 107 defer workertest.DirtyKill(c, lf) 108 109 s.sender.waitForSend(c) 110 workertest.CleanKill(c, lf) 111 s.sender.stub.CheckCalls(c, []testing.StubCall{ 112 {"Send", []interface{}{[]logfwd.Record{s.rec}}}, 113 {"Close", nil}, 114 }) 115 } 116 117 func (s *LogForwarderSuite) TestConfigChange(c *gc.C) { 118 rec0 := s.rec 119 rec1 := s.rec 120 rec1.ID = 11 121 122 api := &mockLogForwardConfig{ 123 enabled: true, 124 host: "10.0.0.1", 125 } 126 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgsWithAPI(c, api, s.stream, s.sender)) 127 c.Assert(err, jc.ErrorIsNil) 128 defer workertest.DirtyKill(c, lf) 129 130 // Send the first record. 131 s.stream.addRecords(c, rec0) 132 s.sender.waitForSend(c) 133 134 // Config change. 135 api.host = "10.0.0.2" 136 api.changes <- struct{}{} 137 s.sender.waitForClose(c) 138 139 // Send the second record. 140 s.stream.addRecords(c, rec1) 141 s.sender.waitForSend(c) 142 143 workertest.CleanKill(c, lf) 144 145 // Check that both records were sent with the config change 146 // applied for the second send. 147 rec1.Message = "send to 10.0.0.2" 148 s.sender.stub.CheckCalls(c, []testing.StubCall{ 149 {"Send", []interface{}{[]logfwd.Record{rec0}}}, 150 {"Close", nil}, 151 {"Send", []interface{}{[]logfwd.Record{rec1}}}, 152 {"Close", nil}, 153 }) 154 } 155 156 func (s *LogForwarderSuite) TestNotEnabled(c *gc.C) { 157 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, nil, s.sender)) 158 c.Assert(err, jc.ErrorIsNil) 159 160 time.Sleep(coretesting.ShortWait) 161 workertest.CleanKill(c, lf) 162 163 // There should be no stream or sender activity when log 164 // forwarding is disabled. 165 s.stream.stub.CheckCallNames(c) 166 s.sender.stub.CheckCallNames(c) 167 } 168 169 func (s *LogForwarderSuite) TestStreamError(c *gc.C) { 170 failure := errors.New("<failure>") 171 s.stream.stub.SetErrors(nil, failure) 172 s.stream.addRecords(c, s.rec) 173 174 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender)) 175 c.Assert(err, jc.ErrorIsNil) 176 defer workertest.DirtyKill(c, lf) 177 178 err = workertest.CheckKilled(c, lf) 179 c.Check(errors.Cause(err), gc.Equals, failure) 180 181 s.sender.stub.CheckCalls(c, []testing.StubCall{ 182 {"Send", []interface{}{[]logfwd.Record{s.rec}}}, 183 {"Close", nil}, 184 }) 185 } 186 187 func (s *LogForwarderSuite) TestSenderError(c *gc.C) { 188 failure := errors.New("<failure>") 189 s.sender.stub.SetErrors(nil, failure) 190 191 rec0 := s.rec 192 rec1 := s.rec 193 rec1.ID = 11 194 s.stream.addRecords(c, rec0, rec1) 195 196 lf, err := logforwarder.NewLogForwarder(s.newLogForwarderArgs(c, s.stream, s.sender)) 197 c.Assert(err, jc.ErrorIsNil) 198 defer workertest.DirtyKill(c, lf) 199 200 err = workertest.CheckKilled(c, lf) 201 c.Check(errors.Cause(err), gc.Equals, failure) 202 203 s.sender.stub.CheckCalls(c, []testing.StubCall{ 204 {"Send", []interface{}{[]logfwd.Record{rec0}}}, 205 {"Send", []interface{}{[]logfwd.Record{rec1}}}, 206 {"Close", nil}, 207 }) 208 } 209 210 type mockLogForwardConfig struct { 211 enabled bool 212 host string 213 changes chan struct{} 214 } 215 216 type mockWatcher struct { 217 watcher.NotifyWatcher 218 changes chan struct{} 219 } 220 221 func (m *mockWatcher) Changes() watcher.NotifyChannel { 222 return m.changes 223 } 224 225 func (*mockWatcher) Kill() { 226 } 227 228 func (*mockWatcher) Wait() error { 229 return nil 230 } 231 232 type mockCaller struct { 233 base.APICaller 234 } 235 236 func (*mockCaller) APICall(objType string, version int, id, request string, params, response interface{}) error { 237 return nil 238 } 239 240 func (*mockCaller) BestFacadeVersion(facade string) int { 241 return 0 242 } 243 244 func (c *mockLogForwardConfig) WatchForLogForwardConfigChanges() (watcher.NotifyWatcher, error) { 245 c.changes = make(chan struct{}, 1) 246 c.changes <- struct{}{} 247 return &mockWatcher{ 248 changes: c.changes, 249 }, nil 250 } 251 252 func (c *mockLogForwardConfig) LogForwardConfig() (*syslog.RawConfig, bool, error) { 253 return &syslog.RawConfig{ 254 Enabled: c.enabled, 255 Host: c.host, 256 CACert: coretesting.CACert, 257 ClientCert: coretesting.ServerCert, 258 ClientKey: coretesting.ServerKey, 259 }, true, nil 260 } 261 262 type stubStream struct { 263 stub *testing.Stub 264 nextRecs chan logfwd.Record 265 } 266 267 func newStubStream() *stubStream { 268 return &stubStream{ 269 stub: new(testing.Stub), 270 nextRecs: make(chan logfwd.Record, 16), 271 } 272 } 273 274 func (s *stubStream) addRecords(c *gc.C, recs ...logfwd.Record) { 275 for _, rec := range recs { 276 s.nextRecs <- rec 277 } 278 } 279 280 func (s *stubStream) Next() ([]logfwd.Record, error) { 281 s.stub.AddCall("Next") 282 if err := s.stub.NextErr(); err != nil { 283 return []logfwd.Record{}, errors.Trace(err) 284 } 285 return []logfwd.Record{<-s.nextRecs}, nil 286 } 287 288 type stubSender struct { 289 stub *testing.Stub 290 activity chan string 291 host string 292 } 293 294 func newStubSender() *stubSender { 295 return &stubSender{ 296 stub: new(testing.Stub), 297 activity: make(chan string, 16), 298 } 299 } 300 301 func (s *stubSender) Send(records []logfwd.Record) error { 302 for i, rec := range records { 303 rec.Message = "send to " + s.host 304 records[i] = rec 305 } 306 s.stub.AddCall("Send", records) 307 s.activity <- "Send" 308 return errors.Trace(s.stub.NextErr()) 309 } 310 311 func (s *stubSender) Close() error { 312 s.stub.AddCall("Close") 313 s.activity <- "Close" 314 return errors.Trace(s.stub.NextErr()) 315 } 316 317 func (s *stubSender) waitForSend(c *gc.C) { 318 s.waitForActivity(c, "Send") 319 } 320 321 func (s *stubSender) waitForClose(c *gc.C) { 322 s.waitForActivity(c, "Close") 323 } 324 325 func (s *stubSender) waitForActivity(c *gc.C, name string) { 326 select { 327 case a := <-s.activity: 328 if a != name { 329 c.Fatalf("expected %v, got %v", name, a) 330 } 331 case <-time.After(coretesting.LongWait): 332 c.Fatalf("timeout out waiting for %v", name) 333 } 334 }