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

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	"github.com/juju/worker/v3/workertest"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/state"
    15  	statetesting "github.com/juju/juju/state/testing"
    16  )
    17  
    18  type statePoolSuite struct {
    19  	statetesting.StateSuite
    20  	State1, State2                    *state.State
    21  	ModelUUID, ModelUUID1, ModelUUID2 string
    22  }
    23  
    24  var _ = gc.Suite(&statePoolSuite{})
    25  
    26  func (s *statePoolSuite) SetUpTest(c *gc.C) {
    27  	s.StateSuite.SetUpTest(c)
    28  	s.ModelUUID = s.State.ModelUUID()
    29  
    30  	s.State1 = s.Factory.MakeModel(c, nil)
    31  	s.AddCleanup(func(*gc.C) { s.State1.Close() })
    32  	s.ModelUUID1 = s.State1.ModelUUID()
    33  
    34  	s.State2 = s.Factory.MakeModel(c, nil)
    35  	s.AddCleanup(func(*gc.C) { s.State2.Close() })
    36  	s.ModelUUID2 = s.State2.ModelUUID()
    37  }
    38  
    39  func (s *statePoolSuite) TestGet(c *gc.C) {
    40  	st1, err := s.StatePool.Get(s.ModelUUID1)
    41  	c.Assert(err, jc.ErrorIsNil)
    42  	c.Assert(st1.ModelUUID(), gc.Equals, s.ModelUUID1)
    43  
    44  	st2, err := s.StatePool.Get(s.ModelUUID2)
    45  	c.Assert(err, jc.ErrorIsNil)
    46  	c.Assert(st2.ModelUUID(), gc.Equals, s.ModelUUID2)
    47  
    48  	// Check that the same instances are returned
    49  	// when a State for the same model is re-requested.
    50  	st1_, err := s.StatePool.Get(s.ModelUUID1)
    51  	c.Assert(err, jc.ErrorIsNil)
    52  	c.Assert(st1_.State, gc.Equals, st1.State)
    53  
    54  	st2_, err := s.StatePool.Get(s.ModelUUID2)
    55  	c.Assert(err, jc.ErrorIsNil)
    56  	c.Assert(st2_.State, gc.Equals, st2.State)
    57  }
    58  
    59  func (s *statePoolSuite) TestGetWithControllerModel(c *gc.C) {
    60  	// When a State for the controller model is requested, the same
    61  	// State that was original passed in should be returned.
    62  	st0, err := s.StatePool.Get(s.ModelUUID)
    63  	c.Assert(err, jc.ErrorIsNil)
    64  	c.Assert(st0.State, gc.Equals, s.State)
    65  }
    66  
    67  func (s *statePoolSuite) TestGetSystemState(c *gc.C) {
    68  	st0, err := s.StatePool.SystemState()
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	c.Assert(st0, gc.Equals, s.State)
    71  }
    72  
    73  func (s *statePoolSuite) TestSystemStateErrorPoolIsClosed(c *gc.C) {
    74  	err := s.StatePool.Close()
    75  	c.Assert(err, jc.ErrorIsNil)
    76  	_, errSysState := s.StatePool.SystemState()
    77  	c.Assert(errSysState, gc.ErrorMatches, "pool is closed")
    78  }
    79  
    80  func (s *statePoolSuite) TestClose(c *gc.C) {
    81  	// Get some State instances.
    82  	st1, err := s.StatePool.Get(s.ModelUUID1)
    83  	c.Assert(err, jc.ErrorIsNil)
    84  
    85  	st2, err := s.StatePool.Get(s.ModelUUID2)
    86  	c.Assert(err, jc.ErrorIsNil)
    87  
    88  	// Now close them.
    89  	err = s.StatePool.Close()
    90  	c.Assert(err, jc.ErrorIsNil)
    91  
    92  	assertStateClosed := func(st *state.State) {
    93  		err := st.Ping()
    94  		c.Assert(err, gc.ErrorMatches, "Closed explicitly")
    95  	}
    96  
    97  	assertStateClosed(s.State)
    98  	assertStateClosed(st1.State)
    99  	assertStateClosed(st2.State)
   100  
   101  	// Requests to Get and GetModel now return errors.
   102  	st1_, err := s.StatePool.Get(s.ModelUUID1)
   103  	c.Assert(err, gc.ErrorMatches, "pool is closed")
   104  	c.Assert(st1_, gc.IsNil)
   105  
   106  	st2_, err := s.StatePool.Get(s.ModelUUID2)
   107  	c.Assert(err, gc.ErrorMatches, "pool is closed")
   108  	c.Assert(st2_, gc.IsNil)
   109  }
   110  
   111  func (s *statePoolSuite) TestTooManyReleases(c *gc.C) {
   112  	st1, err := s.StatePool.Get(s.ModelUUID1)
   113  	c.Assert(err, jc.ErrorIsNil)
   114  	// Get a second reference to the same model
   115  	st2, err := s.StatePool.Get(s.ModelUUID1)
   116  	c.Assert(err, jc.ErrorIsNil)
   117  
   118  	// Try to call the first releaser twice.
   119  	st1.Release()
   120  	st1.Release()
   121  
   122  	removed, err := s.StatePool.Remove(s.ModelUUID1)
   123  	c.Assert(err, jc.ErrorIsNil)
   124  	c.Assert(removed, jc.IsFalse)
   125  
   126  	// Not closed because r2 has not been called.
   127  	assertNotClosed(c, st1.State)
   128  
   129  	removed = st2.Release()
   130  	c.Assert(removed, jc.IsTrue)
   131  	assertClosed(c, st1.State)
   132  }
   133  
   134  func (s *statePoolSuite) TestReleaseOnSystemStateUUID(c *gc.C) {
   135  	st, err := s.StatePool.Get(s.ModelUUID)
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	removed := st.Release()
   138  	c.Assert(removed, jc.IsFalse)
   139  	assertNotClosed(c, st.State)
   140  }
   141  
   142  func (s *statePoolSuite) TestRemoveSystemStateUUID(c *gc.C) {
   143  	removed, err := s.StatePool.Remove(s.ModelUUID)
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	c.Assert(removed, jc.IsFalse)
   146  	assertNotClosed(c, s.State)
   147  }
   148  
   149  func assertNotClosed(c *gc.C, st *state.State) {
   150  	_, err := st.Model()
   151  	c.Assert(err, jc.ErrorIsNil)
   152  }
   153  
   154  func assertClosed(c *gc.C, st *state.State) {
   155  	w := state.GetInternalWorkers(st)
   156  	c.Check(workertest.CheckKilled(c, w), jc.ErrorIsNil)
   157  }
   158  
   159  func (s *statePoolSuite) TestRemoveWithNoRefsCloses(c *gc.C) {
   160  	st, err := s.StatePool.Get(s.ModelUUID1)
   161  	c.Assert(err, jc.ErrorIsNil)
   162  
   163  	// Confirm the state isn't closed.
   164  	removed := st.Release()
   165  	c.Assert(removed, jc.IsFalse)
   166  	assertNotClosed(c, st.State)
   167  
   168  	removed, err = s.StatePool.Remove(s.ModelUUID1)
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	c.Assert(removed, jc.IsTrue)
   171  
   172  	assertClosed(c, st.State)
   173  }
   174  
   175  func (s *statePoolSuite) TestRemoveWithRefsClosesOnLastRelease(c *gc.C) {
   176  	st, err := s.StatePool.Get(s.ModelUUID1)
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	st2, err := s.StatePool.Get(s.ModelUUID1)
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	// Now there are two references to the state.
   181  	// Sanity check!
   182  	assertNotClosed(c, st.State)
   183  
   184  	// Doesn't close while there are refs still held.
   185  	removed, err := s.StatePool.Remove(s.ModelUUID1)
   186  	c.Assert(err, jc.ErrorIsNil)
   187  	c.Assert(removed, jc.IsFalse)
   188  	assertNotClosed(c, st.State)
   189  
   190  	removed = st.Release()
   191  	// Hasn't been closed - still one outstanding reference.
   192  	c.Assert(removed, jc.IsFalse)
   193  	assertNotClosed(c, st.State)
   194  
   195  	// Should be closed when it's released back into the pool.
   196  	removed = st2.Release()
   197  	c.Assert(removed, jc.IsTrue)
   198  	assertClosed(c, st.State)
   199  }
   200  
   201  func (s *statePoolSuite) TestGetRemovedNotAllowed(c *gc.C) {
   202  	_, err := s.StatePool.Get(s.ModelUUID1)
   203  	c.Assert(err, jc.ErrorIsNil)
   204  	_, err = s.StatePool.Remove(s.ModelUUID1)
   205  	c.Assert(err, jc.ErrorIsNil)
   206  	_, err = s.StatePool.Get(s.ModelUUID1)
   207  	c.Assert(err, gc.ErrorMatches, fmt.Sprintf("model %v has been removed", s.ModelUUID1))
   208  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   209  }
   210  
   211  func (s *statePoolSuite) TestReport(c *gc.C) {
   212  	report := s.StatePool.Report()
   213  	c.Check(report, gc.HasLen, 3)
   214  }