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  }