~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/worker/uniter/runner/util_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2015 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package runner_test
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "os"
 
9
        "path/filepath"
 
10
        "runtime"
 
11
        "strings"
 
12
        "time"
 
13
 
 
14
        jc "github.com/juju/testing/checkers"
 
15
        "github.com/juju/utils"
 
16
        "github.com/juju/utils/fs"
 
17
        gc "gopkg.in/check.v1"
 
18
        "gopkg.in/juju/names.v2"
 
19
 
 
20
        "github.com/juju/juju/api"
 
21
        "github.com/juju/juju/api/uniter"
 
22
        "github.com/juju/juju/instance"
 
23
        "github.com/juju/juju/juju/testing"
 
24
        "github.com/juju/juju/network"
 
25
        "github.com/juju/juju/state"
 
26
        "github.com/juju/juju/storage"
 
27
        "github.com/juju/juju/testcharms"
 
28
        coretesting "github.com/juju/juju/testing"
 
29
        "github.com/juju/juju/worker/uniter/runner"
 
30
        "github.com/juju/juju/worker/uniter/runner/context"
 
31
        runnertesting "github.com/juju/juju/worker/uniter/runner/testing"
 
32
)
 
33
 
 
34
var apiAddrs = []string{"a1:123", "a2:123"}
 
35
 
 
36
type ContextSuite struct {
 
37
        testing.JujuConnSuite
 
38
 
 
39
        paths          runnertesting.RealPaths
 
40
        factory        runner.Factory
 
41
        contextFactory context.ContextFactory
 
42
        membership     map[int][]string
 
43
 
 
44
        st      api.Connection
 
45
        service *state.Application
 
46
        machine *state.Machine
 
47
        unit    *state.Unit
 
48
        uniter  *uniter.State
 
49
        apiUnit *uniter.Unit
 
50
        storage *runnertesting.StorageContextAccessor
 
51
 
 
52
        apiRelunits map[int]*uniter.RelationUnit
 
53
        relch       *state.Charm
 
54
        relunits    map[int]*state.RelationUnit
 
55
}
 
56
 
 
57
func (s *ContextSuite) SetUpTest(c *gc.C) {
 
58
        s.JujuConnSuite.SetUpTest(c)
 
59
 
 
60
        s.machine = nil
 
61
 
 
62
        ch := s.AddTestingCharm(c, "wordpress")
 
63
        s.service = s.AddTestingService(c, "u", ch)
 
64
        s.unit = s.AddUnit(c, s.service)
 
65
 
 
66
        storageData0 := names.NewStorageTag("data/0")
 
67
        s.storage = &runnertesting.StorageContextAccessor{
 
68
                map[names.StorageTag]*runnertesting.ContextStorage{
 
69
                        storageData0: &runnertesting.ContextStorage{
 
70
                                storageData0,
 
71
                                storage.StorageKindBlock,
 
72
                                "/dev/sdb",
 
73
                        },
 
74
                },
 
75
        }
 
76
 
 
77
        password, err := utils.RandomPassword()
 
78
        err = s.unit.SetPassword(password)
 
79
        c.Assert(err, jc.ErrorIsNil)
 
80
        s.st = s.OpenAPIAs(c, s.unit.Tag(), password)
 
81
        s.uniter, err = s.st.Uniter()
 
82
        c.Assert(err, jc.ErrorIsNil)
 
83
        c.Assert(s.uniter, gc.NotNil)
 
84
        s.apiUnit, err = s.uniter.Unit(s.unit.Tag().(names.UnitTag))
 
85
        c.Assert(err, jc.ErrorIsNil)
 
86
 
 
87
        s.paths = runnertesting.NewRealPaths(c)
 
88
        s.membership = map[int][]string{}
 
89
 
 
90
        // Note: The unit must always have a charm URL set, because this
 
91
        // happens as part of the installation process (that happens
 
92
        // before the initial install hook).
 
93
        err = s.unit.SetCharmURL(ch.URL())
 
94
        c.Assert(err, jc.ErrorIsNil)
 
95
        s.relch = s.AddTestingCharm(c, "mysql")
 
96
        s.relunits = map[int]*state.RelationUnit{}
 
97
        s.apiRelunits = map[int]*uniter.RelationUnit{}
 
98
        s.AddContextRelation(c, "db0")
 
99
        s.AddContextRelation(c, "db1")
 
100
 
 
101
        s.contextFactory, err = context.NewContextFactory(
 
102
                s.uniter,
 
103
                s.unit.Tag().(names.UnitTag),
 
104
                runnertesting.FakeTracker{},
 
105
                s.getRelationInfos,
 
106
                s.storage,
 
107
                s.paths,
 
108
                coretesting.NewClock(time.Time{}),
 
109
        )
 
110
        c.Assert(err, jc.ErrorIsNil)
 
111
 
 
112
        factory, err := runner.NewFactory(
 
113
                s.uniter,
 
114
                s.paths,
 
115
                s.contextFactory,
 
116
        )
 
117
        c.Assert(err, jc.ErrorIsNil)
 
118
        s.factory = factory
 
119
}
 
120
 
 
121
func (s *ContextSuite) AddContextRelation(c *gc.C, name string) {
 
122
        s.AddTestingService(c, name, s.relch)
 
123
        eps, err := s.State.InferEndpoints("u", name)
 
124
        c.Assert(err, jc.ErrorIsNil)
 
125
        rel, err := s.State.AddRelation(eps...)
 
126
        c.Assert(err, jc.ErrorIsNil)
 
127
        ru, err := rel.Unit(s.unit)
 
128
        c.Assert(err, jc.ErrorIsNil)
 
129
        err = ru.EnterScope(map[string]interface{}{"relation-name": name})
 
130
        c.Assert(err, jc.ErrorIsNil)
 
131
        s.relunits[rel.Id()] = ru
 
132
        apiRel, err := s.uniter.Relation(rel.Tag().(names.RelationTag))
 
133
        c.Assert(err, jc.ErrorIsNil)
 
134
        apiRelUnit, err := apiRel.Unit(s.apiUnit)
 
135
        c.Assert(err, jc.ErrorIsNil)
 
136
        s.apiRelunits[rel.Id()] = apiRelUnit
 
137
}
 
138
 
 
139
func (s *ContextSuite) AddUnit(c *gc.C, svc *state.Application) *state.Unit {
 
140
        unit, err := svc.AddUnit()
 
141
        c.Assert(err, jc.ErrorIsNil)
 
142
        if s.machine != nil {
 
143
                err = unit.AssignToMachine(s.machine)
 
144
                c.Assert(err, jc.ErrorIsNil)
 
145
                return unit
 
146
        }
 
147
 
 
148
        err = s.State.AssignUnit(unit, state.AssignCleanEmpty)
 
149
        c.Assert(err, jc.ErrorIsNil)
 
150
        machineId, err := unit.AssignedMachineId()
 
151
        c.Assert(err, jc.ErrorIsNil)
 
152
        s.machine, err = s.State.Machine(machineId)
 
153
        c.Assert(err, jc.ErrorIsNil)
 
154
        zone := "a-zone"
 
155
        hwc := instance.HardwareCharacteristics{
 
156
                AvailabilityZone: &zone,
 
157
        }
 
158
        err = s.machine.SetProvisioned("i-exist", "fake_nonce", &hwc)
 
159
        c.Assert(err, jc.ErrorIsNil)
 
160
 
 
161
        name := strings.Replace(unit.Name(), "/", "-", 1)
 
162
        privateAddr := network.NewScopedAddress(name+".testing.invalid", network.ScopeCloudLocal)
 
163
        err = s.machine.SetProviderAddresses(privateAddr)
 
164
        c.Assert(err, jc.ErrorIsNil)
 
165
        return unit
 
166
}
 
167
 
 
168
func (s *ContextSuite) SetCharm(c *gc.C, name string) {
 
169
        err := os.RemoveAll(s.paths.GetCharmDir())
 
170
        c.Assert(err, jc.ErrorIsNil)
 
171
        err = fs.Copy(testcharms.Repo.CharmDirPath(name), s.paths.GetCharmDir())
 
172
        c.Assert(err, jc.ErrorIsNil)
 
173
}
 
174
 
 
175
func (s *ContextSuite) getRelationInfos() map[int]*context.RelationInfo {
 
176
        info := map[int]*context.RelationInfo{}
 
177
        for relId, relUnit := range s.apiRelunits {
 
178
                info[relId] = &context.RelationInfo{
 
179
                        RelationUnit: relUnit,
 
180
                        MemberNames:  s.membership[relId],
 
181
                }
 
182
        }
 
183
        return info
 
184
}
 
185
 
 
186
// hookSpec supports makeCharm.
 
187
type hookSpec struct {
 
188
        // dir is the directory to create the hook in.
 
189
        dir string
 
190
        // name is the name of the hook.
 
191
        name string
 
192
        // perm is the file permissions of the hook.
 
193
        perm os.FileMode
 
194
        // code is the exit status of the hook.
 
195
        code int
 
196
        // stdout holds a string to print to stdout
 
197
        stdout string
 
198
        // stderr holds a string to print to stderr
 
199
        stderr string
 
200
        // background holds a string to print in the background after 0.2s.
 
201
        background string
 
202
}
 
203
 
 
204
// makeCharm constructs a fake charm dir containing a single named hook
 
205
// with permissions perm and exit code code. If output is non-empty,
 
206
// the charm will write it to stdout and stderr, with each one prefixed
 
207
// by name of the stream.
 
208
func makeCharm(c *gc.C, spec hookSpec, charmDir string) {
 
209
        dir := charmDir
 
210
        if spec.dir != "" {
 
211
                dir = filepath.Join(dir, spec.dir)
 
212
                err := os.Mkdir(dir, 0755)
 
213
                c.Assert(err, jc.ErrorIsNil)
 
214
        }
 
215
        c.Logf("openfile perm %v", spec.perm)
 
216
        hook, err := os.OpenFile(
 
217
                filepath.Join(dir, spec.name), os.O_CREATE|os.O_WRONLY, spec.perm,
 
218
        )
 
219
        c.Assert(err, jc.ErrorIsNil)
 
220
        defer func() {
 
221
                c.Assert(hook.Close(), gc.IsNil)
 
222
        }()
 
223
 
 
224
        printf := func(f string, a ...interface{}) {
 
225
                _, err := fmt.Fprintf(hook, f+"\n", a...)
 
226
                c.Assert(err, jc.ErrorIsNil)
 
227
        }
 
228
        if runtime.GOOS != "windows" {
 
229
                printf("#!/bin/bash")
 
230
        }
 
231
        printf(echoPidScript)
 
232
        if spec.stdout != "" {
 
233
                printf("echo %s", spec.stdout)
 
234
        }
 
235
        if spec.stderr != "" {
 
236
                printf("echo %s >&2", spec.stderr)
 
237
        }
 
238
        if spec.background != "" {
 
239
                // Print something fairly quickly, then sleep for
 
240
                // quite a long time - if the hook execution is
 
241
                // blocking because of the background process,
 
242
                // the hook execution will take much longer than
 
243
                // expected.
 
244
                printf("(sleep 0.2; echo %s; sleep 10) &", spec.background)
 
245
        }
 
246
        printf("exit %d", spec.code)
 
247
}