github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/deployer/deployer_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package deployer_test
     5  
     6  import (
     7  	stdtesting "testing"
     8  
     9  	"github.com/juju/names/v5"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/api"
    14  	"github.com/juju/juju/api/agent/deployer"
    15  	"github.com/juju/juju/core/life"
    16  	"github.com/juju/juju/core/network"
    17  	"github.com/juju/juju/core/status"
    18  	"github.com/juju/juju/core/watcher/watchertest"
    19  	"github.com/juju/juju/juju/testing"
    20  	"github.com/juju/juju/rpc/params"
    21  	"github.com/juju/juju/state"
    22  	coretesting "github.com/juju/juju/testing"
    23  )
    24  
    25  func TestAll(t *stdtesting.T) {
    26  	coretesting.MgoTestPackage(t)
    27  }
    28  
    29  type deployerSuite struct {
    30  	testing.JujuConnSuite
    31  
    32  	stateAPI api.Connection
    33  
    34  	// These are raw State objects. Use them for setup and assertions, but
    35  	// should never be touched by the API calls themselves
    36  	machine     *state.Machine
    37  	app0        *state.Application
    38  	app1        *state.Application
    39  	principal   *state.Unit
    40  	subordinate *state.Unit
    41  
    42  	st *deployer.State
    43  }
    44  
    45  var _ = gc.Suite(&deployerSuite{})
    46  
    47  func (s *deployerSuite) SetUpTest(c *gc.C) {
    48  	s.JujuConnSuite.SetUpTest(c)
    49  	s.stateAPI, s.machine = s.OpenAPIAsNewMachine(c, state.JobManageModel, state.JobHostUnits)
    50  	err := s.machine.SetProviderAddresses(network.NewSpaceAddress("0.1.2.3"))
    51  	c.Assert(err, jc.ErrorIsNil)
    52  
    53  	// Create the needed applications and relate them.
    54  	s.app0 = s.AddTestingApplication(c, "mysql", s.AddTestingCharm(c, "mysql"))
    55  	s.app1 = s.AddTestingApplication(c, "logging", s.AddTestingCharm(c, "logging"))
    56  	eps, err := s.State.InferEndpoints("mysql", "logging")
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	rel, err := s.State.AddRelation(eps...)
    59  	c.Assert(err, jc.ErrorIsNil)
    60  
    61  	// Create principal and subordinate units and assign them.
    62  	s.principal, err = s.app0.AddUnit(state.AddUnitParams{})
    63  	c.Assert(err, jc.ErrorIsNil)
    64  	err = s.principal.AssignToMachine(s.machine)
    65  	c.Assert(err, jc.ErrorIsNil)
    66  	relUnit, err := rel.Unit(s.principal)
    67  	c.Assert(err, jc.ErrorIsNil)
    68  	err = relUnit.EnterScope(nil)
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	s.subordinate, err = s.State.Unit("logging/0")
    71  	c.Assert(err, jc.ErrorIsNil)
    72  
    73  	// Create the deployer facade.
    74  	s.st = deployer.NewState(s.stateAPI)
    75  	c.Assert(s.st, gc.NotNil)
    76  }
    77  
    78  // Note: This is really meant as a unit-test, this isn't a test that
    79  // should need all of the setup we have for this test suite
    80  func (s *deployerSuite) TestNew(c *gc.C) {
    81  	deployer := deployer.NewState(s.stateAPI)
    82  	c.Assert(deployer, gc.NotNil)
    83  }
    84  
    85  func (s *deployerSuite) assertUnauthorized(c *gc.C, err error) {
    86  	c.Assert(err, gc.ErrorMatches, "permission denied")
    87  	c.Assert(err, jc.Satisfies, params.IsCodeUnauthorized)
    88  }
    89  
    90  func (s *deployerSuite) TestWatchUnitsWrongMachine(c *gc.C) {
    91  	// Try with a non-existent machine tag.
    92  	machine, err := s.st.Machine(names.NewMachineTag("42"))
    93  	c.Assert(err, jc.ErrorIsNil)
    94  	w, err := machine.WatchUnits()
    95  	s.assertUnauthorized(c, err)
    96  	c.Assert(w, gc.IsNil)
    97  }
    98  
    99  func (s *deployerSuite) TestWatchUnits(c *gc.C) {
   100  	// TODO(dfc) fix state.Machine to return a MachineTag
   101  	machine, err := s.st.Machine(s.machine.Tag().(names.MachineTag))
   102  	c.Assert(err, jc.ErrorIsNil)
   103  	w, err := machine.WatchUnits()
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	wc := watchertest.NewStringsWatcherC(c, w)
   106  	defer wc.AssertStops()
   107  
   108  	// Initial event.
   109  	wc.AssertChange("mysql/0", "logging/0")
   110  	wc.AssertNoChange()
   111  
   112  	// Change something other than the lifecycle and make sure it's
   113  	// not detected.
   114  	err = s.subordinate.SetPassword("foo")
   115  	c.Assert(err, gc.ErrorMatches, "password is only 3 bytes long, and is not a valid Agent password")
   116  	wc.AssertNoChange()
   117  
   118  	err = s.subordinate.SetPassword("foo-12345678901234567890")
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	wc.AssertNoChange()
   121  
   122  	// Make the subordinate dead and check it's detected.
   123  	err = s.subordinate.EnsureDead()
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	wc.AssertChange("logging/0")
   126  	wc.AssertNoChange()
   127  }
   128  
   129  func (s *deployerSuite) TestUnit(c *gc.C) {
   130  	// Try getting a missing unit and an invalid tag.
   131  	unit, err := s.st.Unit(names.NewUnitTag("foo/42"))
   132  	s.assertUnauthorized(c, err)
   133  	c.Assert(unit, gc.IsNil)
   134  
   135  	// Try getting a unit we're not responsible for.
   136  	// First create a new machine and deploy another unit there.
   137  	machine, err := s.State.AddMachine(state.UbuntuBase("12.10"), state.JobHostUnits)
   138  	c.Assert(err, jc.ErrorIsNil)
   139  	principal1, err := s.app0.AddUnit(state.AddUnitParams{})
   140  	c.Assert(err, jc.ErrorIsNil)
   141  	err = principal1.AssignToMachine(machine)
   142  	c.Assert(err, jc.ErrorIsNil)
   143  	unit, err = s.st.Unit(principal1.Tag().(names.UnitTag))
   144  	s.assertUnauthorized(c, err)
   145  	c.Assert(unit, gc.IsNil)
   146  
   147  	// Get the principal and subordinate we're responsible for.
   148  	unit, err = s.st.Unit(s.principal.Tag().(names.UnitTag))
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	c.Assert(unit.Name(), gc.Equals, "mysql/0")
   151  	unit, err = s.st.Unit(s.subordinate.Tag().(names.UnitTag))
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	c.Assert(unit.Name(), gc.Equals, "logging/0")
   154  }
   155  
   156  func (s *deployerSuite) TestUnitLifeRefresh(c *gc.C) {
   157  	unit, err := s.st.Unit(s.subordinate.Tag().(names.UnitTag))
   158  	c.Assert(err, jc.ErrorIsNil)
   159  
   160  	c.Assert(unit.Life(), gc.Equals, life.Alive)
   161  
   162  	// Now make it dead and check again, then refresh and check.
   163  	err = s.subordinate.EnsureDead()
   164  	c.Assert(err, jc.ErrorIsNil)
   165  	err = s.subordinate.Refresh()
   166  	c.Assert(err, jc.ErrorIsNil)
   167  	c.Assert(s.subordinate.Life(), gc.Equals, state.Dead)
   168  	c.Assert(unit.Life(), gc.Equals, life.Alive)
   169  	err = unit.Refresh()
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	c.Assert(unit.Life(), gc.Equals, life.Dead)
   172  }
   173  
   174  func (s *deployerSuite) TestUnitRemove(c *gc.C) {
   175  	unit, err := s.st.Unit(s.principal.Tag().(names.UnitTag))
   176  	c.Assert(err, jc.ErrorIsNil)
   177  
   178  	// It fails because the entity is still alive.
   179  	// And EnsureDead will fail because there is a subordinate.
   180  	err = unit.Remove()
   181  	c.Assert(err, gc.ErrorMatches, `cannot remove entity "unit-mysql-0": still alive`)
   182  	c.Assert(params.ErrCode(err), gc.Equals, "")
   183  
   184  	// With the subordinate it also fails due to it being alive.
   185  	unit, err = s.st.Unit(s.subordinate.Tag().(names.UnitTag))
   186  	c.Assert(err, jc.ErrorIsNil)
   187  	err = unit.Remove()
   188  	c.Assert(err, gc.ErrorMatches, `cannot remove entity "unit-logging-0": still alive`)
   189  	c.Assert(params.ErrCode(err), gc.Equals, "")
   190  
   191  	// Make it dead first and try again.
   192  	err = s.subordinate.EnsureDead()
   193  	c.Assert(err, jc.ErrorIsNil)
   194  	err = unit.Remove()
   195  	c.Assert(err, jc.ErrorIsNil)
   196  
   197  	// Verify it's gone.
   198  	err = unit.Refresh()
   199  	s.assertUnauthorized(c, err)
   200  	unit, err = s.st.Unit(s.subordinate.Tag().(names.UnitTag))
   201  	s.assertUnauthorized(c, err)
   202  	c.Assert(unit, gc.IsNil)
   203  }
   204  
   205  func (s *deployerSuite) TestUnitSetPassword(c *gc.C) {
   206  	unit, err := s.st.Unit(s.principal.Tag().(names.UnitTag))
   207  	c.Assert(err, jc.ErrorIsNil)
   208  
   209  	// Change the principal's password and verify.
   210  	err = unit.SetPassword("foobar-12345678901234567890")
   211  	c.Assert(err, jc.ErrorIsNil)
   212  	err = s.principal.Refresh()
   213  	c.Assert(err, jc.ErrorIsNil)
   214  	c.Assert(s.principal.PasswordValid("foobar-12345678901234567890"), jc.IsTrue)
   215  
   216  	// Then the subordinate.
   217  	unit, err = s.st.Unit(s.subordinate.Tag().(names.UnitTag))
   218  	c.Assert(err, jc.ErrorIsNil)
   219  	err = unit.SetPassword("phony-12345678901234567890")
   220  	c.Assert(err, jc.ErrorIsNil)
   221  	err = s.subordinate.Refresh()
   222  	c.Assert(err, jc.ErrorIsNil)
   223  	c.Assert(s.subordinate.PasswordValid("phony-12345678901234567890"), jc.IsTrue)
   224  }
   225  
   226  func (s *deployerSuite) TestUnitSetStatus(c *gc.C) {
   227  	unit, err := s.st.Unit(s.principal.Tag().(names.UnitTag))
   228  	c.Assert(err, jc.ErrorIsNil)
   229  	err = unit.SetStatus(status.Blocked, "waiting", map[string]interface{}{"foo": "bar"})
   230  	c.Assert(err, jc.ErrorIsNil)
   231  
   232  	stateUnit, err := s.BackingState.Unit(unit.Name())
   233  	c.Assert(err, jc.ErrorIsNil)
   234  	sInfo, err := stateUnit.Status()
   235  	c.Assert(err, jc.ErrorIsNil)
   236  	sInfo.Since = nil
   237  	c.Assert(sInfo, jc.DeepEquals, status.StatusInfo{
   238  		Status:  status.Blocked,
   239  		Message: "waiting",
   240  		Data:    map[string]interface{}{"foo": "bar"},
   241  	})
   242  }