1
// Copyright 2015 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
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"
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"
34
var apiAddrs = []string{"a1:123", "a2:123"}
36
type ContextSuite struct {
39
paths runnertesting.RealPaths
40
factory runner.Factory
41
contextFactory context.ContextFactory
42
membership map[int][]string
45
service *state.Application
46
machine *state.Machine
50
storage *runnertesting.StorageContextAccessor
52
apiRelunits map[int]*uniter.RelationUnit
54
relunits map[int]*state.RelationUnit
57
func (s *ContextSuite) SetUpTest(c *gc.C) {
58
s.JujuConnSuite.SetUpTest(c)
62
ch := s.AddTestingCharm(c, "wordpress")
63
s.service = s.AddTestingService(c, "u", ch)
64
s.unit = s.AddUnit(c, s.service)
66
storageData0 := names.NewStorageTag("data/0")
67
s.storage = &runnertesting.StorageContextAccessor{
68
map[names.StorageTag]*runnertesting.ContextStorage{
69
storageData0: &runnertesting.ContextStorage{
71
storage.StorageKindBlock,
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)
87
s.paths = runnertesting.NewRealPaths(c)
88
s.membership = map[int][]string{}
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")
101
s.contextFactory, err = context.NewContextFactory(
103
s.unit.Tag().(names.UnitTag),
104
runnertesting.FakeTracker{},
108
coretesting.NewClock(time.Time{}),
110
c.Assert(err, jc.ErrorIsNil)
112
factory, err := runner.NewFactory(
117
c.Assert(err, jc.ErrorIsNil)
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
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)
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)
155
hwc := instance.HardwareCharacteristics{
156
AvailabilityZone: &zone,
158
err = s.machine.SetProvisioned("i-exist", "fake_nonce", &hwc)
159
c.Assert(err, jc.ErrorIsNil)
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)
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)
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],
186
// hookSpec supports makeCharm.
187
type hookSpec struct {
188
// dir is the directory to create the hook in.
190
// name is the name of the hook.
192
// perm is the file permissions of the hook.
194
// code is the exit status of the hook.
196
// stdout holds a string to print to stdout
198
// stderr holds a string to print to stderr
200
// background holds a string to print in the background after 0.2s.
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) {
211
dir = filepath.Join(dir, spec.dir)
212
err := os.Mkdir(dir, 0755)
213
c.Assert(err, jc.ErrorIsNil)
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,
219
c.Assert(err, jc.ErrorIsNil)
221
c.Assert(hook.Close(), gc.IsNil)
224
printf := func(f string, a ...interface{}) {
225
_, err := fmt.Fprintf(hook, f+"\n", a...)
226
c.Assert(err, jc.ErrorIsNil)
228
if runtime.GOOS != "windows" {
229
printf("#!/bin/bash")
231
printf(echoPidScript)
232
if spec.stdout != "" {
233
printf("echo %s", spec.stdout)
235
if spec.stderr != "" {
236
printf("echo %s >&2", spec.stderr)
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
244
printf("(sleep 0.2; echo %s; sleep 10) &", spec.background)
246
printf("exit %d", spec.code)