github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/state/meterstatus_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/mgo/v3/bson"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/state"
    14  	statetesting "github.com/juju/juju/state/testing"
    15  )
    16  
    17  type MeterStateSuite struct {
    18  	ConnSuite
    19  	unit           *state.Unit
    20  	metricsManager *state.MetricsManager
    21  }
    22  
    23  var _ = gc.Suite(&MeterStateSuite{})
    24  
    25  func (s *MeterStateSuite) SetUpTest(c *gc.C) {
    26  	s.ConnSuite.SetUpTest(c)
    27  	s.unit = s.Factory.MakeUnit(c, nil)
    28  	c.Assert(s.unit.Base(), jc.DeepEquals, state.Base{OS: "ubuntu", Channel: "12.10/stable"})
    29  	var err error
    30  	s.metricsManager, err = s.State.MetricsManager()
    31  	c.Assert(err, jc.ErrorIsNil)
    32  	// Before we get into the tests, ensure that all the creation events have flowed through the system.
    33  	s.WaitForModelWatchersIdle(c, s.Model.UUID())
    34  }
    35  
    36  func (s *MeterStateSuite) TestMeterStatus(c *gc.C) {
    37  	status, err := s.unit.GetMeterStatus()
    38  	c.Assert(err, jc.ErrorIsNil)
    39  	c.Assert(status.Code, gc.Equals, state.MeterNotSet)
    40  	err = s.unit.SetMeterStatus("GREEN", "Additional information.")
    41  	c.Assert(err, jc.ErrorIsNil)
    42  	status, err = s.unit.GetMeterStatus()
    43  	c.Assert(err, jc.ErrorIsNil)
    44  	c.Assert(status.Code, gc.Equals, state.MeterGreen)
    45  }
    46  
    47  func (s *MeterStateSuite) TestMeterStatusIncludesModelUUID(c *gc.C) {
    48  	jujuDB := s.MgoSuite.Session.DB("juju")
    49  	meterStatus := jujuDB.C("meterStatus")
    50  	var docs []bson.M
    51  	err := meterStatus.Find(nil).All(&docs)
    52  	c.Assert(err, jc.ErrorIsNil)
    53  	// we now expect two meter status docs - one for the unit and one
    54  	// for the model - both should have the model-uuid filled in.
    55  	c.Assert(docs, gc.HasLen, 2)
    56  	c.Assert(docs[0]["model-uuid"], gc.Equals, s.State.ModelUUID())
    57  	c.Assert(docs[1]["model-uuid"], gc.Equals, s.State.ModelUUID())
    58  }
    59  
    60  func (s *MeterStateSuite) TestSetMeterStatusIncorrect(c *gc.C) {
    61  	err := s.unit.SetMeterStatus("NOT SET", "Additional information.")
    62  	c.Assert(err, gc.ErrorMatches, `meter status "NOT SET" not valid`)
    63  	status, err := s.unit.GetMeterStatus()
    64  	c.Assert(err, jc.ErrorIsNil)
    65  	c.Assert(status.Code, gc.Equals, state.MeterNotSet)
    66  
    67  	err = s.unit.SetMeterStatus("this-is-not-a-valid-status", "Additional information.")
    68  	c.Assert(err, gc.ErrorMatches, `meter status "this-is-not-a-valid-status" not valid`)
    69  	status, err = s.unit.GetMeterStatus()
    70  	c.Assert(err, jc.ErrorIsNil)
    71  	c.Assert(status.Code, gc.Equals, state.MeterNotSet)
    72  }
    73  
    74  func (s *MeterStateSuite) TestSetMeterStatusWhenDying(c *gc.C) {
    75  	preventUnitDestroyRemove(c, s.unit)
    76  	testWhenDying(c, s.unit, ".*"+contentionErr, contentionErr, func() error {
    77  		err := s.unit.SetMeterStatus("GREEN", "Additional information.")
    78  		if err != nil {
    79  			return err
    80  		}
    81  		status, err := s.unit.GetMeterStatus()
    82  		c.Assert(err, jc.ErrorIsNil)
    83  		c.Assert(status.Code, gc.Equals, state.MeterNotSet)
    84  		return nil
    85  	})
    86  }
    87  
    88  func (s *MeterStateSuite) TestMeterStatusRemovedWithUnit(c *gc.C) {
    89  	err := s.unit.SetMeterStatus("GREEN", "Information.")
    90  	c.Assert(err, jc.ErrorIsNil)
    91  	err = s.unit.EnsureDead()
    92  	c.Assert(err, jc.ErrorIsNil)
    93  	err = s.unit.Remove()
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	status, err := s.unit.GetMeterStatus()
    96  	c.Assert(err, gc.ErrorMatches, "cannot retrieve meter status for unit .*: not found")
    97  	c.Assert(status.Code, gc.Equals, state.MeterNotAvailable)
    98  }
    99  
   100  func (s *MeterStateSuite) TestMeterStatusWatcherRespondstoMeterStatus(c *gc.C) {
   101  	watcher := s.unit.WatchMeterStatus()
   102  	wc := statetesting.NewNotifyWatcherC(c, watcher)
   103  	wc.AssertOneChange()
   104  	err := s.unit.SetMeterStatus("GREEN", "Information.")
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	wc.AssertOneChange()
   107  }
   108  
   109  func (s *MeterStateSuite) TestMeterStatusWatcherRespondsToMetricsManager(c *gc.C) {
   110  	mm, err := s.State.MetricsManager()
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	watcher := s.unit.WatchMeterStatus()
   113  	wc := statetesting.NewNotifyWatcherC(c, watcher)
   114  	wc.AssertOneChange()
   115  	err = mm.SetLastSuccessfulSend(s.Clock.Now())
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	wc.AssertOneChange()
   118  	for i := 0; i < 3; i++ {
   119  		err := mm.IncrementConsecutiveErrors()
   120  		c.Assert(err, jc.ErrorIsNil)
   121  	}
   122  	status := mm.MeterStatus()
   123  	c.Assert(status.Code, gc.Equals, state.MeterAmber)
   124  	wc.AssertOneChange()
   125  }
   126  
   127  func (s *MeterStateSuite) TestMeterStatusWatcherRespondsToMetricsManagerAndStatus(c *gc.C) {
   128  	mm, err := s.State.MetricsManager()
   129  	c.Assert(err, jc.ErrorIsNil)
   130  	watcher := s.unit.WatchMeterStatus()
   131  	wc := statetesting.NewNotifyWatcherC(c, watcher)
   132  	wc.AssertOneChange()
   133  	err = mm.SetLastSuccessfulSend(s.Clock.Now())
   134  	c.Assert(err, jc.ErrorIsNil)
   135  	wc.AssertOneChange()
   136  	for i := 0; i < 3; i++ {
   137  		err := mm.IncrementConsecutiveErrors()
   138  		c.Assert(err, jc.ErrorIsNil)
   139  	}
   140  	status := mm.MeterStatus()
   141  	c.Assert(status.Code, gc.Equals, state.MeterAmber)
   142  	wc.AssertOneChange()
   143  	err = s.unit.SetMeterStatus("GREEN", "Information.")
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	wc.AssertOneChange()
   146  }
   147  
   148  func (s *MeterStateSuite) assertMetricsManagerAmberState(c *gc.C, metricsManager *state.MetricsManager) {
   149  	err := metricsManager.SetLastSuccessfulSend(s.Clock.Now())
   150  	c.Assert(err, jc.ErrorIsNil)
   151  	for i := 0; i < 3; i++ {
   152  		err := metricsManager.IncrementConsecutiveErrors()
   153  		c.Assert(err, jc.ErrorIsNil)
   154  	}
   155  	status := metricsManager.MeterStatus()
   156  	c.Assert(status.Code, gc.Equals, state.MeterAmber, gc.Commentf("got meter status %#v", status))
   157  }
   158  
   159  // TODO (mattyw) This function could be moved into a metricsmanager testing package.
   160  func (s *MeterStateSuite) assertMetricsManagerRedState(c *gc.C, metricsManager *state.MetricsManager) {
   161  	// To enter the red state we need to set a last successful send as over 1 week ago
   162  	err := metricsManager.SetLastSuccessfulSend(s.Clock.Now().Add(-8 * 24 * time.Hour))
   163  	c.Assert(err, jc.ErrorIsNil)
   164  	for i := 0; i < 3; i++ {
   165  		err := metricsManager.IncrementConsecutiveErrors()
   166  		c.Assert(err, jc.ErrorIsNil)
   167  	}
   168  	status := metricsManager.MeterStatus()
   169  	c.Assert(status.Code, gc.Equals, state.MeterRed, gc.Commentf("got meter status %#v", status))
   170  }
   171  
   172  // TestMeterStatusMetricsManagerCombinations test every possible combination
   173  // of meter status from the unit and the metrics manager.
   174  func (s *MeterStateSuite) TestMeterStatusMetricsManagerCombinations(c *gc.C) {
   175  	greenMetricsMangager := func() {}
   176  	amberMetricsManager := func() {
   177  		s.assertMetricsManagerAmberState(c, s.metricsManager)
   178  	}
   179  	redMetricsManager := func() {
   180  		s.assertMetricsManagerRedState(c, s.metricsManager)
   181  	}
   182  	greenUnit := func() {
   183  		err := s.unit.SetMeterStatus("GREEN", "Unit")
   184  		c.Assert(err, jc.ErrorIsNil)
   185  	}
   186  	amberUnit := func() {
   187  		err := s.unit.SetMeterStatus("AMBER", "Unit")
   188  		c.Assert(err, jc.ErrorIsNil)
   189  	}
   190  	redUnit := func() {
   191  		err := s.unit.SetMeterStatus("RED", "Unit")
   192  		c.Assert(err, jc.ErrorIsNil)
   193  	}
   194  
   195  	tests := []struct {
   196  		about          string
   197  		metricsManager func()
   198  		unit           func()
   199  		expectedCode   state.MeterStatusCode
   200  		expectedInfo   string
   201  	}{{
   202  		"green metrics manager and green unit returns green overall",
   203  		greenMetricsMangager,
   204  		greenUnit,
   205  		state.MeterGreen,
   206  		"Unit",
   207  	}, {
   208  		"amber metrics manager and amber unit returns amber overall",
   209  		amberMetricsManager,
   210  		amberUnit,
   211  		state.MeterAmber,
   212  		"Unit",
   213  	}, {
   214  		"red metrics manager and red unit returns red overall",
   215  		redMetricsManager,
   216  		redUnit,
   217  		state.MeterRed,
   218  		"failed to send metrics, exceeded grace period",
   219  	}, {
   220  
   221  		"red metrics manager and amber unit returns red overall",
   222  		redMetricsManager,
   223  		amberUnit,
   224  		state.MeterRed,
   225  		"failed to send metrics, exceeded grace period",
   226  	}, {
   227  		"red metrics manager and green unit returns red overall",
   228  		redMetricsManager,
   229  		greenUnit,
   230  		state.MeterRed,
   231  		"failed to send metrics, exceeded grace period",
   232  	}, {
   233  		"amber metrics manager and red unit returns red overall",
   234  		amberMetricsManager,
   235  		redUnit,
   236  		state.MeterRed,
   237  		"Unit",
   238  	}, {
   239  		"amber metrics manager and green unit returns amber overall",
   240  		amberMetricsManager,
   241  		greenUnit,
   242  		state.MeterAmber,
   243  		"failed to send metrics",
   244  	}, {
   245  		"green metrics manager and red unit returns red overall",
   246  		greenMetricsMangager,
   247  		redUnit,
   248  		state.MeterRed,
   249  		"Unit",
   250  	}, {
   251  		"green metrics manager and amber unit returns amber overall",
   252  		greenMetricsMangager,
   253  		amberUnit,
   254  		state.MeterAmber,
   255  		"Unit",
   256  	}}
   257  
   258  	for i, test := range tests {
   259  		c.Logf("running test %d %s", i, test.about)
   260  		test.metricsManager()
   261  		test.unit()
   262  		status, err := s.unit.GetMeterStatus()
   263  		c.Assert(err, jc.ErrorIsNil)
   264  		c.Check(status.Code, gc.Equals, test.expectedCode, gc.Commentf("got meter status %#v", status))
   265  	}
   266  }
   267  
   268  func (s *MeterStateSuite) TestMeterStatusCombination(c *gc.C) {
   269  	var (
   270  		Red          = state.MeterStatus{state.MeterRed, ""}
   271  		Amber        = state.MeterStatus{state.MeterAmber, ""}
   272  		Green        = state.MeterStatus{state.MeterGreen, ""}
   273  		NotSet       = state.MeterStatus{state.MeterNotSet, ""}
   274  		NotAvailable = state.MeterStatus{state.MeterNotAvailable, ""}
   275  	)
   276  	c.Assert(state.CombineMeterStatus(Red, Red).Code, gc.Equals, Red.Code)
   277  	c.Assert(state.CombineMeterStatus(Red, Amber).Code, gc.Equals, Red.Code)
   278  	c.Assert(state.CombineMeterStatus(Red, Green).Code, gc.Equals, Red.Code)
   279  	c.Assert(state.CombineMeterStatus(Red, NotSet).Code, gc.Equals, Red.Code)
   280  	c.Assert(state.CombineMeterStatus(Red, NotAvailable).Code, gc.Equals, NotAvailable.Code)
   281  
   282  	c.Assert(state.CombineMeterStatus(Amber, Red).Code, gc.Equals, Red.Code)
   283  	c.Assert(state.CombineMeterStatus(Amber, Amber).Code, gc.Equals, Amber.Code)
   284  	c.Assert(state.CombineMeterStatus(Amber, Green).Code, gc.Equals, Amber.Code)
   285  	c.Assert(state.CombineMeterStatus(Amber, NotSet).Code, gc.Equals, Amber.Code)
   286  	c.Assert(state.CombineMeterStatus(Amber, NotAvailable).Code, gc.Equals, NotAvailable.Code)
   287  
   288  	c.Assert(state.CombineMeterStatus(Green, Red).Code, gc.Equals, Red.Code)
   289  	c.Assert(state.CombineMeterStatus(Green, Amber).Code, gc.Equals, Amber.Code)
   290  	c.Assert(state.CombineMeterStatus(Green, Green).Code, gc.Equals, Green.Code)
   291  	c.Assert(state.CombineMeterStatus(Green, NotSet).Code, gc.Equals, NotSet.Code)
   292  	c.Assert(state.CombineMeterStatus(Green, NotAvailable).Code, gc.Equals, NotAvailable.Code)
   293  
   294  	c.Assert(state.CombineMeterStatus(NotSet, Red).Code, gc.Equals, Red.Code)
   295  	c.Assert(state.CombineMeterStatus(NotSet, Amber).Code, gc.Equals, Amber.Code)
   296  	c.Assert(state.CombineMeterStatus(NotSet, Green).Code, gc.Equals, NotSet.Code)
   297  	c.Assert(state.CombineMeterStatus(NotSet, NotSet).Code, gc.Equals, NotSet.Code)
   298  	c.Assert(state.CombineMeterStatus(NotSet, NotAvailable).Code, gc.Equals, NotAvailable.Code)
   299  
   300  	c.Assert(state.CombineMeterStatus(NotAvailable, Red).Code, gc.Equals, NotAvailable.Code)
   301  	c.Assert(state.CombineMeterStatus(NotAvailable, Amber).Code, gc.Equals, NotAvailable.Code)
   302  	c.Assert(state.CombineMeterStatus(NotAvailable, Green).Code, gc.Equals, NotAvailable.Code)
   303  	c.Assert(state.CombineMeterStatus(NotAvailable, NotSet).Code, gc.Equals, NotAvailable.Code)
   304  	c.Assert(state.CombineMeterStatus(NotAvailable, NotAvailable).Code, gc.Equals, NotAvailable.Code)
   305  }