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 }