github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/worker/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 "runtime" 8 "sort" 9 "strings" 10 stdtesting "testing" 11 "time" 12 13 "github.com/juju/errors" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/api" 18 apideployer "github.com/juju/juju/api/deployer" 19 jujutesting "github.com/juju/juju/juju/testing" 20 "github.com/juju/juju/state" 21 coretesting "github.com/juju/juju/testing" 22 "github.com/juju/juju/worker" 23 "github.com/juju/juju/worker/deployer" 24 ) 25 26 func TestPackage(t *stdtesting.T) { 27 //TODO(bogdanteleaga): Fix this on windows 28 if runtime.GOOS == "windows" { 29 t.Skip("bug 1403084: Currently does not work under windows") 30 } 31 coretesting.MgoTestPackage(t) 32 } 33 34 type deployerSuite struct { 35 jujutesting.JujuConnSuite 36 SimpleToolsFixture 37 38 machine *state.Machine 39 stateAPI api.Connection 40 deployerState *apideployer.State 41 } 42 43 var _ = gc.Suite(&deployerSuite{}) 44 45 var _ worker.StringsWatchHandler = (*deployer.Deployer)(nil) 46 47 func (s *deployerSuite) SetUpTest(c *gc.C) { 48 s.JujuConnSuite.SetUpTest(c) 49 s.SimpleToolsFixture.SetUp(c, s.DataDir()) 50 s.stateAPI, s.machine = s.OpenAPIAsNewMachine(c) 51 // Create the deployer facade. 52 s.deployerState = s.stateAPI.Deployer() 53 c.Assert(s.deployerState, gc.NotNil) 54 } 55 56 func (s *deployerSuite) TearDownTest(c *gc.C) { 57 s.SimpleToolsFixture.TearDown(c) 58 s.JujuConnSuite.TearDownTest(c) 59 } 60 61 func (s *deployerSuite) makeDeployerAndContext(c *gc.C) (worker.Worker, deployer.Context) { 62 // Create a deployer acting on behalf of the machine. 63 ctx := s.getContextForMachine(c, s.machine.Tag()) 64 return deployer.NewDeployer(s.deployerState, ctx), ctx 65 } 66 67 func (s *deployerSuite) TestDeployRecallRemovePrincipals(c *gc.C) { 68 // Create a machine, and a couple of units. 69 svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 70 u0, err := svc.AddUnit() 71 c.Assert(err, jc.ErrorIsNil) 72 u1, err := svc.AddUnit() 73 c.Assert(err, jc.ErrorIsNil) 74 75 dep, ctx := s.makeDeployerAndContext(c) 76 defer stop(c, dep) 77 78 // Assign one unit, and wait for it to be deployed. 79 err = u0.AssignToMachine(s.machine) 80 c.Assert(err, jc.ErrorIsNil) 81 s.waitFor(c, isDeployed(ctx, u0.Name())) 82 83 // Assign another unit, and wait for that to be deployed. 84 err = u1.AssignToMachine(s.machine) 85 c.Assert(err, jc.ErrorIsNil) 86 s.waitFor(c, isDeployed(ctx, u0.Name(), u1.Name())) 87 88 // Cause a unit to become Dying, and check no change. 89 err = u1.SetAgentStatus(state.StatusIdle, "", nil) 90 c.Assert(err, jc.ErrorIsNil) 91 err = u1.Destroy() 92 c.Assert(err, jc.ErrorIsNil) 93 s.waitFor(c, isDeployed(ctx, u0.Name(), u1.Name())) 94 95 // Cause a unit to become Dead, and check that it is both recalled and 96 // removed from state. 97 err = u0.EnsureDead() 98 c.Assert(err, jc.ErrorIsNil) 99 s.waitFor(c, isRemoved(s.State, u0.Name())) 100 s.waitFor(c, isDeployed(ctx, u1.Name())) 101 102 // Remove the Dying unit from the machine, and check that it is recalled... 103 err = u1.UnassignFromMachine() 104 c.Assert(err, jc.ErrorIsNil) 105 s.waitFor(c, isDeployed(ctx)) 106 107 // ...and that the deployer, no longer bearing any responsibility for the 108 // Dying unit, does nothing further to it. 109 err = u1.Refresh() 110 c.Assert(err, jc.ErrorIsNil) 111 c.Assert(u1.Life(), gc.Equals, state.Dying) 112 } 113 114 func (s *deployerSuite) TestRemoveNonAlivePrincipals(c *gc.C) { 115 // Create a service, and a couple of units. 116 svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 117 u0, err := svc.AddUnit() 118 c.Assert(err, jc.ErrorIsNil) 119 u1, err := svc.AddUnit() 120 c.Assert(err, jc.ErrorIsNil) 121 122 // Assign the units to the machine, and set them to Dying/Dead. 123 err = u0.AssignToMachine(s.machine) 124 c.Assert(err, jc.ErrorIsNil) 125 err = u0.EnsureDead() 126 c.Assert(err, jc.ErrorIsNil) 127 err = u1.AssignToMachine(s.machine) 128 c.Assert(err, jc.ErrorIsNil) 129 // note: this is not a sane state; for the unit to have a status it must 130 // have been deployed. But it's instructive to check that the right thing 131 // would happen if it were possible to have a dying unit in this situation. 132 err = u1.SetAgentStatus(state.StatusIdle, "", nil) 133 c.Assert(err, jc.ErrorIsNil) 134 err = u1.Destroy() 135 c.Assert(err, jc.ErrorIsNil) 136 137 // When the deployer is started, in each case (1) no unit agent is deployed 138 // and (2) the non-Alive unit is been removed from state. 139 dep, ctx := s.makeDeployerAndContext(c) 140 defer stop(c, dep) 141 s.waitFor(c, isRemoved(s.State, u0.Name())) 142 s.waitFor(c, isRemoved(s.State, u1.Name())) 143 s.waitFor(c, isDeployed(ctx)) 144 } 145 146 func (s *deployerSuite) prepareSubordinates(c *gc.C) (*state.Unit, []*state.RelationUnit) { 147 svc := s.AddTestingService(c, "wordpress", s.AddTestingCharm(c, "wordpress")) 148 u, err := svc.AddUnit() 149 c.Assert(err, jc.ErrorIsNil) 150 err = u.AssignToMachine(s.machine) 151 c.Assert(err, jc.ErrorIsNil) 152 rus := []*state.RelationUnit{} 153 logging := s.AddTestingCharm(c, "logging") 154 for _, name := range []string{"subsvc0", "subsvc1"} { 155 s.AddTestingService(c, name, logging) 156 eps, err := s.State.InferEndpoints("wordpress", name) 157 c.Assert(err, jc.ErrorIsNil) 158 rel, err := s.State.AddRelation(eps...) 159 c.Assert(err, jc.ErrorIsNil) 160 ru, err := rel.Unit(u) 161 c.Assert(err, jc.ErrorIsNil) 162 rus = append(rus, ru) 163 } 164 return u, rus 165 } 166 167 func (s *deployerSuite) TestDeployRecallRemoveSubordinates(c *gc.C) { 168 // Create a deployer acting on behalf of the principal. 169 u, rus := s.prepareSubordinates(c) 170 dep, ctx := s.makeDeployerAndContext(c) 171 defer stop(c, dep) 172 173 // Add a subordinate, and wait for it to be deployed. 174 err := rus[0].EnterScope(nil) 175 c.Assert(err, jc.ErrorIsNil) 176 sub0, err := s.State.Unit("subsvc0/0") 177 c.Assert(err, jc.ErrorIsNil) 178 // Make sure the principal is deployed first, then the subordinate 179 s.waitFor(c, isDeployed(ctx, u.Name(), sub0.Name())) 180 181 // And another. 182 err = rus[1].EnterScope(nil) 183 c.Assert(err, jc.ErrorIsNil) 184 sub1, err := s.State.Unit("subsvc1/0") 185 c.Assert(err, jc.ErrorIsNil) 186 s.waitFor(c, isDeployed(ctx, u.Name(), sub0.Name(), sub1.Name())) 187 188 // Set one to Dying; check nothing happens. 189 err = sub1.Destroy() 190 c.Assert(err, jc.ErrorIsNil) 191 s.State.StartSync() 192 c.Assert(isRemoved(s.State, sub1.Name())(c), jc.IsFalse) 193 s.waitFor(c, isDeployed(ctx, u.Name(), sub0.Name(), sub1.Name())) 194 195 // Set the other to Dead; check it's recalled and removed. 196 err = sub0.EnsureDead() 197 c.Assert(err, jc.ErrorIsNil) 198 s.waitFor(c, isDeployed(ctx, u.Name(), sub1.Name())) 199 s.waitFor(c, isRemoved(s.State, sub0.Name())) 200 } 201 202 func (s *deployerSuite) TestNonAliveSubordinates(c *gc.C) { 203 // Add two subordinate units and set them to Dead/Dying respectively. 204 _, rus := s.prepareSubordinates(c) 205 err := rus[0].EnterScope(nil) 206 c.Assert(err, jc.ErrorIsNil) 207 sub0, err := s.State.Unit("subsvc0/0") 208 c.Assert(err, jc.ErrorIsNil) 209 err = sub0.EnsureDead() 210 c.Assert(err, jc.ErrorIsNil) 211 err = rus[1].EnterScope(nil) 212 c.Assert(err, jc.ErrorIsNil) 213 sub1, err := s.State.Unit("subsvc1/0") 214 c.Assert(err, jc.ErrorIsNil) 215 err = sub1.Destroy() 216 c.Assert(err, jc.ErrorIsNil) 217 218 // When we start a new deployer, neither unit will be deployed and 219 // both will be removed. 220 dep, _ := s.makeDeployerAndContext(c) 221 defer stop(c, dep) 222 s.waitFor(c, isRemoved(s.State, sub0.Name())) 223 s.waitFor(c, isRemoved(s.State, sub1.Name())) 224 } 225 226 func (s *deployerSuite) waitFor(c *gc.C, t func(c *gc.C) bool) { 227 s.BackingState.StartSync() 228 if t(c) { 229 return 230 } 231 timeout := time.After(coretesting.LongWait) 232 for { 233 select { 234 case <-timeout: 235 c.Fatalf("timeout") 236 case <-time.After(coretesting.ShortWait): 237 if t(c) { 238 return 239 } 240 } 241 } 242 } 243 244 func isDeployed(ctx deployer.Context, expected ...string) func(*gc.C) bool { 245 return func(c *gc.C) bool { 246 sort.Strings(expected) 247 current, err := ctx.DeployedUnits() 248 c.Assert(err, jc.ErrorIsNil) 249 sort.Strings(current) 250 return strings.Join(expected, ":") == strings.Join(current, ":") 251 } 252 } 253 254 func isRemoved(st *state.State, name string) func(*gc.C) bool { 255 return func(c *gc.C) bool { 256 _, err := st.Unit(name) 257 if errors.IsNotFound(err) { 258 return true 259 } 260 c.Assert(err, jc.ErrorIsNil) 261 return false 262 } 263 } 264 265 func stop(c *gc.C, w worker.Worker) { 266 c.Assert(worker.Stop(w), gc.IsNil) 267 }