~juju-qa/ubuntu/trusty/juju/juju-1.25.8

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/worker/deployer/deployer_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-12-02 18:01:10 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161202180110-dl1helep8qfebmhx
ImportĀ upstreamĀ 1.25.6

Show diffs side-by-side

added added

removed removed

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