github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/logs_internal_test.go (about) 1 // Copyright 2019 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package state 5 6 import ( 7 "fmt" 8 "time" 9 10 "github.com/dustin/go-humanize" 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 "github.com/juju/mgo/v3" 14 "github.com/juju/mgo/v3/bson" 15 mgotesting "github.com/juju/mgo/v3/testing" 16 "github.com/juju/testing" 17 jc "github.com/juju/testing/checkers" 18 gc "gopkg.in/check.v1" 19 20 corelogger "github.com/juju/juju/core/logger" 21 ) 22 23 type LogsInternalSuite struct { 24 mgotesting.MgoSuite 25 testing.IsolationSuite 26 } 27 28 var _ = gc.Suite(&LogsInternalSuite{}) 29 30 func (s *LogsInternalSuite) SetUpSuite(c *gc.C) { 31 s.DebugMgo = true 32 s.MgoSuite.SetUpSuite(c) 33 s.IsolationSuite.SetUpSuite(c) 34 } 35 36 func (s *LogsInternalSuite) TearDownSuite(c *gc.C) { 37 s.IsolationSuite.TearDownSuite(c) 38 s.MgoSuite.TearDownSuite(c) 39 } 40 41 func (s *LogsInternalSuite) SetUpTest(c *gc.C) { 42 s.MgoSuite.SetUpTest(c) 43 s.IsolationSuite.SetUpTest(c) 44 } 45 46 func (s *LogsInternalSuite) TearDownTest(c *gc.C) { 47 err := s.Session.DB("logs").DropDatabase() 48 c.Assert(err, jc.ErrorIsNil) 49 s.IsolationSuite.TearDownTest(c) 50 s.MgoSuite.TearDownTest(c) 51 } 52 53 func (s *LogsInternalSuite) TestCollStatsForMissingDB(c *gc.C) { 54 coll := s.Session.DB("logs").C("missing") 55 _, err := collStats(coll) 56 57 c.Assert(err.Error(), gc.Equals, "Collection [logs.missing] not found") 58 c.Assert(err, jc.Satisfies, errors.IsNotFound) 59 } 60 61 func (s *LogsInternalSuite) createLogsDB(c *gc.C) *mgo.Collection { 62 // We create the db by writing something into a collection. 63 coll := s.Session.DB("logs").C("new") 64 err := coll.Insert(bson.M{"_id": "new"}) 65 c.Assert(err, jc.ErrorIsNil) 66 return coll 67 } 68 69 func (s *LogsInternalSuite) createCapped(c *gc.C, name string, size int) *mgo.Collection { 70 // We create the db by writing something into a collection. 71 coll := s.Session.DB("logs").C(name) 72 err := coll.Create(&mgo.CollectionInfo{ 73 Capped: true, 74 MaxBytes: size, 75 }) 76 c.Assert(err, jc.ErrorIsNil) 77 return coll 78 } 79 80 func (s *LogsInternalSuite) TestCollStatsForMissingCollection(c *gc.C) { 81 // Create a collection in the logs database to make sure the DB exists. 82 s.createLogsDB(c) 83 84 coll := s.Session.DB("logs").C("missing") 85 _, err := collStats(coll) 86 87 c.Assert(err.Error(), gc.Equals, "Collection [logs.missing] not found") 88 c.Assert(err, jc.Satisfies, errors.IsNotFound) 89 } 90 91 func (s *LogsInternalSuite) TestCappedInfoForNormalCollection(c *gc.C) { 92 coll := s.createLogsDB(c) 93 94 capped, maxSize, err := getCollectionCappedInfo(coll) 95 c.Assert(err, jc.ErrorIsNil) 96 c.Assert(capped, jc.IsFalse) 97 c.Assert(maxSize, gc.Equals, 0) 98 } 99 100 func (s *LogsInternalSuite) TestCappedInfoForCappedCollection(c *gc.C) { 101 // mgo MaxBytes is in bytes, whereas we query in MB 102 coll := s.createCapped(c, "capped", 20*1024*1024) 103 104 capped, maxSize, err := getCollectionCappedInfo(coll) 105 c.Assert(err, jc.ErrorIsNil) 106 c.Assert(capped, jc.IsTrue) 107 c.Assert(maxSize, gc.Equals, 20) 108 } 109 110 func (s *LogsInternalSuite) dbLogger(coll *mgo.Collection) *DbLogger { 111 return &DbLogger{ 112 logsColl: coll, 113 modelUUID: "fake-uuid", 114 } 115 } 116 117 func writeSomeLogs(c *gc.C, logger *DbLogger, count int) { 118 toWrite := make([]corelogger.LogRecord, 0, count) 119 when := time.Now() 120 c.Logf("writing %d logs to the db\n", count) 121 for i := 0; i < count; i++ { 122 toWrite = append(toWrite, corelogger.LogRecord{ 123 Time: when, 124 Entity: "some-entity", 125 Level: loggo.DEBUG, 126 Module: "test", 127 Location: "test_file.go:1234", 128 Message: fmt.Sprintf("test line %d", i), 129 }) 130 } 131 err := logger.Log(toWrite) 132 c.Assert(err, jc.ErrorIsNil) 133 } 134 135 func (s *LogsInternalSuite) TestLogsCollectionConversion(c *gc.C) { 136 coll := s.createLogsDB(c) 137 err := convertToCapped(coll, 5) 138 c.Assert(err, jc.ErrorIsNil) 139 140 capped, maxSize, err := getCollectionCappedInfo(coll) 141 c.Assert(err, jc.ErrorIsNil) 142 c.Assert(capped, jc.IsTrue) 143 c.Assert(maxSize, gc.Equals, 5) 144 } 145 146 func (s *LogsInternalSuite) TestLogsCollectionConversionTwice(c *gc.C) { 147 coll := s.createLogsDB(c) 148 err := convertToCapped(coll, 5) 149 c.Assert(err, jc.ErrorIsNil) 150 151 err = convertToCapped(coll, 10) 152 c.Assert(err, jc.ErrorIsNil) 153 154 capped, maxSize, err := getCollectionCappedInfo(coll) 155 c.Assert(err, jc.ErrorIsNil) 156 c.Assert(capped, jc.IsTrue) 157 c.Assert(maxSize, gc.Equals, 10) 158 } 159 160 func (s *LogsInternalSuite) TestLogsCollectionConversionSmallerSize(c *gc.C) { 161 // Create a log db that has two meg of data, then convert it 162 // to a capped collection with a one meg limit. 163 coll := s.createLogsDB(c) 164 dbLogger := s.dbLogger(coll) 165 size := 0 166 for size < 4 { 167 writeSomeLogs(c, dbLogger, 5000) 168 sizeKB, err := getCollectionKB(coll) 169 c.Assert(err, jc.ErrorIsNil) 170 size = sizeKB / humanize.KiByte 171 } 172 173 err := convertToCapped(coll, 2) 174 c.Assert(err, jc.ErrorIsNil) 175 176 capped, maxSize, err := getCollectionCappedInfo(coll) 177 c.Assert(err, jc.ErrorIsNil) 178 c.Assert(capped, jc.IsTrue) 179 c.Assert(maxSize, gc.Equals, 2) 180 181 sizeKB, err := getCollectionKB(coll) 182 c.Assert(err, jc.ErrorIsNil) 183 // We don't have a LessThan or equal to, so using 3 to mean 1 or 2. 184 c.Assert(sizeKB/humanize.KiByte, jc.LessThan, 3) 185 186 // Check that we still have some documents in there. 187 docs, err := coll.Count() 188 c.Assert(err, jc.ErrorIsNil) 189 c.Assert(docs, jc.GreaterThan, 5000) 190 } 191 192 func (s *LogsInternalSuite) TestLogsCollectionConversionTwiceSmallerSize(c *gc.C) { 193 // Create a log db that has two meg of data, then convert it 194 // to a capped collection with a one meg limit. 195 coll := s.createLogsDB(c) 196 dbLogger := s.dbLogger(coll) 197 size := 0 198 for size < 4 { 199 writeSomeLogs(c, dbLogger, 5000) 200 sizeKB, err := getCollectionKB(coll) 201 c.Assert(err, jc.ErrorIsNil) 202 size = sizeKB / humanize.KiByte 203 } 204 205 err := convertToCapped(coll, 10) 206 c.Assert(err, jc.ErrorIsNil) 207 208 // Now resize again to 2. 209 err = convertToCapped(coll, 2) 210 c.Assert(err, jc.ErrorIsNil) 211 212 capped, maxSize, err := getCollectionCappedInfo(coll) 213 c.Assert(err, jc.ErrorIsNil) 214 c.Assert(capped, jc.IsTrue) 215 c.Check(maxSize, gc.Equals, 2) 216 217 sizeKB, err := getCollectionKB(coll) 218 c.Assert(err, jc.ErrorIsNil) 219 // We don't have a LessThan or equal to, so using 3 to mean 1 or 2. 220 c.Assert(sizeKB/humanize.KiByte, jc.LessThan, 3) 221 222 // Check that we still have some documents in there. 223 docs, err := coll.Count() 224 c.Assert(err, jc.ErrorIsNil) 225 c.Assert(docs, jc.GreaterThan, 5000) 226 } 227 228 func (s *LogsInternalSuite) TestLogsCollectionConversionTwiceBiggerSize(c *gc.C) { 229 // Create a log db that has two meg of data, then convert it 230 // to a capped collection with a one meg limit. 231 coll := s.createLogsDB(c) 232 dbLogger := s.dbLogger(coll) 233 size := 0 234 for size < 4 { 235 writeSomeLogs(c, dbLogger, 5000) 236 sizeKB, err := getCollectionKB(coll) 237 c.Assert(err, jc.ErrorIsNil) 238 size = sizeKB / humanize.KiByte 239 } 240 241 err := convertToCapped(coll, 1) 242 c.Assert(err, jc.ErrorIsNil) 243 244 // Now resize again to 2. 245 err = convertToCapped(coll, 2) 246 c.Assert(err, jc.ErrorIsNil) 247 248 capped, maxSize, err := getCollectionCappedInfo(coll) 249 c.Assert(err, jc.ErrorIsNil) 250 c.Assert(capped, jc.IsTrue) 251 c.Check(maxSize, gc.Equals, 2) 252 253 sizeKB, err := getCollectionKB(coll) 254 c.Assert(err, jc.ErrorIsNil) 255 // We don't have a LessThan or equal to, so using 3 to mean 1 or 2. 256 c.Assert(sizeKB/humanize.KiByte, jc.LessThan, 3) 257 258 // Check that we still have some documents in there. 259 docs, err := coll.Count() 260 c.Assert(err, jc.ErrorIsNil) 261 c.Assert(docs, jc.GreaterThan, 5000) 262 } 263 264 type DBLogInitInternalSuite struct { 265 mgotesting.MgoSuite 266 testing.IsolationSuite 267 } 268 269 var _ = gc.Suite(&DBLogInitInternalSuite{}) 270 271 func (s *DBLogInitInternalSuite) SetUpSuite(c *gc.C) { 272 s.DebugMgo = true 273 s.MgoSuite.SetUpSuite(c) 274 s.IsolationSuite.SetUpSuite(c) 275 } 276 277 func (s *DBLogInitInternalSuite) TearDownSuite(c *gc.C) { 278 s.IsolationSuite.TearDownSuite(c) 279 s.MgoSuite.TearDownSuite(c) 280 } 281 282 func (s *DBLogInitInternalSuite) SetUpTest(c *gc.C) { 283 s.MgoSuite.SetUpTest(c) 284 s.IsolationSuite.SetUpTest(c) 285 } 286 287 func (s *DBLogInitInternalSuite) TearDownTest(c *gc.C) { 288 err := s.Session.DB("logs").DropDatabase() 289 c.Assert(err, jc.ErrorIsNil) 290 s.IsolationSuite.TearDownTest(c) 291 s.MgoSuite.TearDownTest(c) 292 } 293 294 func (s *DBLogInitInternalSuite) TestInitDBLogsForModel(c *gc.C) { 295 err := InitDbLogsForModel(s.Session, "foo-bar", 10) 296 c.Assert(err, jc.ErrorIsNil) 297 298 err = InitDbLogsForModel(s.Session, "foo-bar", 10) 299 c.Assert(err, jc.ErrorIsNil) 300 } 301 302 func (s *DBLogInitInternalSuite) TestInitDBLogsForModelConcurrently(c *gc.C) { 303 results := make(chan error) 304 defer close(results) 305 306 for i := 0; i < 2; i++ { 307 go func() { 308 results <- InitDbLogsForModel(s.Session, "foo-bar", 10) 309 }() 310 } 311 var amount int 312 LOOP: 313 for { 314 select { 315 case err := <-results: 316 c.Assert(err, jc.ErrorIsNil) 317 amount++ 318 if amount == 2 { 319 break LOOP 320 } 321 case <-time.After(testing.LongWait): 322 c.Fatal("error timedout waiting for a result") 323 return 324 } 325 } 326 327 c.Assert(amount, gc.Equals, 2) 328 329 coll := s.Session.DB("logs").C(logCollectionName("foo-bar")) 330 capped, maxSize, err := getCollectionCappedInfo(coll) 331 c.Assert(err, jc.ErrorIsNil) 332 c.Assert(capped, jc.IsTrue) 333 c.Check(maxSize, gc.Equals, 10) 334 }