github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/logsender/worker_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package logsender_test 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 "gopkg.in/juju/names.v2" 14 "gopkg.in/mgo.v2" 15 "gopkg.in/mgo.v2/bson" 16 17 "github.com/juju/juju/api" 18 apilogsender "github.com/juju/juju/api/logsender" 19 jujutesting "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/testing" 21 "github.com/juju/juju/testing/factory" 22 "github.com/juju/juju/version" 23 "github.com/juju/juju/worker/logsender" 24 ) 25 26 type workerSuite struct { 27 jujutesting.JujuConnSuite 28 29 // machineTag holds the tag of a machine created 30 // for the test. 31 machineTag names.Tag 32 33 // APIState holds an API connection authenticated 34 // as the above machine. 35 APIState api.Connection 36 } 37 38 var _ = gc.Suite(&workerSuite{}) 39 40 func (s *workerSuite) SetUpTest(c *gc.C) { 41 s.JujuConnSuite.SetUpTest(c) 42 43 // Create a machine for the client to log in as. 44 nonce := "some-nonce" 45 machine, password := s.Factory.MakeMachineReturningPassword(c, 46 &factory.MachineParams{Nonce: nonce}) 47 apiInfo := s.APIInfo(c) 48 apiInfo.Tag = machine.Tag() 49 apiInfo.Password = password 50 apiInfo.Nonce = nonce 51 st, err := api.Open(apiInfo, api.DefaultDialOpts()) 52 c.Assert(err, gc.IsNil) 53 s.APIState = st 54 s.machineTag = machine.Tag() 55 } 56 57 func (s *workerSuite) TearDownTest(c *gc.C) { 58 s.APIState.Close() 59 s.JujuConnSuite.TearDownTest(c) 60 } 61 62 func (s *workerSuite) logSenderAPI() *apilogsender.API { 63 return apilogsender.NewAPI(s.APIState) 64 } 65 66 func (s *workerSuite) TestLogSending(c *gc.C) { 67 const logCount = 5 68 logsCh := make(chan *logsender.LogRecord, logCount) 69 70 // Start the logsender worker. 71 worker := logsender.New(logsCh, s.logSenderAPI()) 72 defer func() { 73 worker.Kill() 74 c.Check(worker.Wait(), jc.ErrorIsNil) 75 }() 76 77 // Send some logs, also building up what should appear in the 78 // database. 79 var expectedDocs []bson.M 80 for i := 0; i < logCount; i++ { 81 ts := time.Now() 82 location := fmt.Sprintf("loc%d", i) 83 message := fmt.Sprintf("%d", i) 84 85 logsCh <- &logsender.LogRecord{ 86 Time: ts, 87 Module: "logsender-test", 88 Location: location, 89 Level: loggo.INFO, 90 Message: message, 91 } 92 93 expectedDocs = append(expectedDocs, bson.M{ 94 "t": ts.UnixNano(), 95 "r": version.Current.String(), 96 "n": s.machineTag.String(), 97 "m": "logsender-test", 98 "l": location, 99 "v": int(loggo.INFO), 100 "x": message, 101 }) 102 } 103 104 // Wait for the logs to appear in the database. 105 var docs []bson.M 106 logsColl := s.logCollection() 107 for a := testing.LongAttempt.Start(); a.Next(); { 108 err := logsColl.Find(bson.M{"m": "logsender-test"}).All(&docs) 109 c.Assert(err, jc.ErrorIsNil) 110 if len(docs) == logCount { 111 break 112 } 113 } 114 115 // Check that the logs are correct. 116 c.Assert(docs, gc.HasLen, logCount) 117 for i := 0; i < logCount; i++ { 118 doc := docs[i] 119 delete(doc, "_id") 120 c.Assert(doc, gc.DeepEquals, expectedDocs[i]) 121 } 122 } 123 124 func (s *workerSuite) logCollection() *mgo.Collection { 125 return s.State.MongoSession().DB("logs").C("logs." + s.State.ModelUUID()) 126 } 127 128 func (s *workerSuite) TestDroppedLogs(c *gc.C) { 129 logsCh := make(logsender.LogRecordCh) 130 131 // Start the logsender worker. 132 worker := logsender.New(logsCh, s.logSenderAPI()) 133 defer func() { 134 worker.Kill() 135 c.Check(worker.Wait(), jc.ErrorIsNil) 136 }() 137 138 // Send a log record which indicates some messages after it were 139 // dropped. 140 ts := time.Now() 141 logsCh <- &logsender.LogRecord{ 142 Time: ts, 143 Module: "aaa", 144 Location: "loc", 145 Level: loggo.INFO, 146 Message: "message0", 147 DroppedAfter: 42, 148 } 149 150 // Send another log record with no drops indicated. 151 logsCh <- &logsender.LogRecord{ 152 Time: time.Now(), 153 Module: "zzz", 154 Location: "loc", 155 Level: loggo.INFO, 156 Message: "message1", 157 } 158 159 // Wait for the logs to appear in the database. 160 var docs []bson.M 161 logsColl := s.logCollection() 162 for a := testing.LongAttempt.Start(); a.Next(); { 163 if !a.HasNext() { 164 c.Fatal("timed out waiting for logs") 165 } 166 err := logsColl.Find(nil).Sort("m").All(&docs) 167 c.Assert(err, jc.ErrorIsNil) 168 // Expect the 2 messages sent along with a message about 169 // dropped messages. 170 if len(docs) == 3 { 171 break 172 } 173 } 174 175 // Check that the log records sent are present as well as an additional 176 // message in between indicating that some messages were dropped. 177 c.Assert(docs[0]["x"], gc.Equals, "message0") 178 delete(docs[1], "_id") 179 c.Assert(docs[1], gc.DeepEquals, bson.M{ 180 "t": ts.UnixNano(), // Should share timestamp with previous message. 181 "r": version.Current.String(), 182 "n": s.machineTag.String(), 183 "m": "juju.worker.logsender", 184 "l": "", 185 "v": int(loggo.WARNING), 186 "x": "42 log messages dropped due to lack of API connectivity", 187 }) 188 c.Assert(docs[2]["x"], gc.Equals, "message1") 189 }