~ubuntu-branches/ubuntu/trusty/juju-core/trusty-proposed

« back to all changes in this revision

Viewing changes to src/launchpad.net/juju-core/state/apiserver/client/run_test.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-29 11:40:20 UTC
  • mfrom: (23.1.1 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20140129114020-ejieitm8smtt5vln
Tags: 1.17.1-0ubuntu2
d/tests/local-provider: Don't fail tests if ~/.juju is present as its
created by the juju version command. 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2013 Canonical Ltd.
 
2
// Licensed under the AGPLv3, see LICENCE file for details.
 
3
 
 
4
package client_test
 
5
 
 
6
import (
 
7
        "fmt"
 
8
        "io/ioutil"
 
9
        "os"
 
10
        "path/filepath"
 
11
        "time"
 
12
 
 
13
        gc "launchpad.net/gocheck"
 
14
 
 
15
        "launchpad.net/juju-core/instance"
 
16
        "launchpad.net/juju-core/state"
 
17
        "launchpad.net/juju-core/state/api/params"
 
18
        "launchpad.net/juju-core/state/apiserver/client"
 
19
        "launchpad.net/juju-core/testing"
 
20
        jc "launchpad.net/juju-core/testing/checkers"
 
21
        "launchpad.net/juju-core/utils/exec"
 
22
        "launchpad.net/juju-core/utils/ssh"
 
23
)
 
24
 
 
25
type runSuite struct {
 
26
        baseSuite
 
27
}
 
28
 
 
29
var _ = gc.Suite(&runSuite{})
 
30
 
 
31
func (s *runSuite) addMachine(c *gc.C) *state.Machine {
 
32
        machine, err := s.State.AddMachine("quantal", state.JobHostUnits)
 
33
        c.Assert(err, gc.IsNil)
 
34
        return machine
 
35
}
 
36
 
 
37
func (s *runSuite) addMachineWithAddress(c *gc.C, address string) *state.Machine {
 
38
        machine := s.addMachine(c)
 
39
        machine.SetAddresses([]instance.Address{instance.NewAddress(address)})
 
40
        return machine
 
41
}
 
42
 
 
43
func (s *runSuite) TestRemoteParamsForMachinePopulates(c *gc.C) {
 
44
        machine := s.addMachine(c)
 
45
        result := client.RemoteParamsForMachine(machine, "command", time.Minute)
 
46
        c.Assert(result.Command, gc.Equals, "command")
 
47
        c.Assert(result.Timeout, gc.Equals, time.Minute)
 
48
        c.Assert(result.MachineId, gc.Equals, machine.Id())
 
49
        // Now an empty host isn't particularly useful, but the machine doesn't
 
50
        // have an address to use.
 
51
        c.Assert(machine.Addresses(), gc.HasLen, 0)
 
52
        c.Assert(result.Host, gc.Equals, "")
 
53
}
 
54
 
 
55
func (s *runSuite) TestRemoteParamsForMachinePopulatesWithAddress(c *gc.C) {
 
56
        machine := s.addMachineWithAddress(c, "10.3.2.1")
 
57
 
 
58
        result := client.RemoteParamsForMachine(machine, "command", time.Minute)
 
59
        c.Assert(result.Command, gc.Equals, "command")
 
60
        c.Assert(result.Timeout, gc.Equals, time.Minute)
 
61
        c.Assert(result.MachineId, gc.Equals, machine.Id())
 
62
        c.Assert(result.Host, gc.Equals, "ubuntu@10.3.2.1")
 
63
}
 
64
 
 
65
func (s *runSuite) addUnit(c *gc.C, service *state.Service) *state.Unit {
 
66
        unit, err := service.AddUnit()
 
67
        c.Assert(err, gc.IsNil)
 
68
        err = unit.AssignToNewMachine()
 
69
        c.Assert(err, gc.IsNil)
 
70
        mId, err := unit.AssignedMachineId()
 
71
        c.Assert(err, gc.IsNil)
 
72
        machine, err := s.State.Machine(mId)
 
73
        c.Assert(err, gc.IsNil)
 
74
        machine.SetAddresses([]instance.Address{instance.NewAddress("10.3.2.1")})
 
75
        return unit
 
76
}
 
77
 
 
78
func (s *runSuite) TestGetAllUnitNames(c *gc.C) {
 
79
        charm := s.AddTestingCharm(c, "dummy")
 
80
        magic, err := s.State.AddService("magic", "user-admin", charm)
 
81
        s.addUnit(c, magic)
 
82
        s.addUnit(c, magic)
 
83
 
 
84
        notAssigned, err := s.State.AddService("not-assigned", "user-admin", charm)
 
85
        c.Assert(err, gc.IsNil)
 
86
        _, err = notAssigned.AddUnit()
 
87
        c.Assert(err, gc.IsNil)
 
88
 
 
89
        _, err = s.State.AddService("no-units", "user-admin", charm)
 
90
        c.Assert(err, gc.IsNil)
 
91
 
 
92
        for i, test := range []struct {
 
93
                message  string
 
94
                expected []string
 
95
                units    []string
 
96
                services []string
 
97
                error    string
 
98
        }{{
 
99
                message: "no units, expected nil slice",
 
100
        }, {
 
101
                message: "asking for a unit that isn't there",
 
102
                units:   []string{"foo/0"},
 
103
                error:   `unit "foo/0" not found`,
 
104
        }, {
 
105
                message:  "asking for a service that isn't there",
 
106
                services: []string{"foo"},
 
107
                error:    `service "foo" not found`,
 
108
        }, {
 
109
                message:  "service with no units is not really an error",
 
110
                services: []string{"no-units"},
 
111
        }, {
 
112
                message:  "A service with units not assigned is an error",
 
113
                services: []string{"not-assigned"},
 
114
                error:    `unit "not-assigned/0" is not assigned to a machine`,
 
115
        }, {
 
116
                message:  "A service with units",
 
117
                services: []string{"magic"},
 
118
                expected: []string{"magic/0", "magic/1"},
 
119
        }, {
 
120
                message:  "Asking for just a unit",
 
121
                units:    []string{"magic/0"},
 
122
                expected: []string{"magic/0"},
 
123
        }, {
 
124
                message:  "Asking for a unit, and the service",
 
125
                services: []string{"magic"},
 
126
                units:    []string{"magic/0"},
 
127
                expected: []string{"magic/0", "magic/1"},
 
128
        }} {
 
129
                c.Logf("%v: %s", i, test.message)
 
130
                result, err := client.GetAllUnitNames(s.State, test.units, test.services)
 
131
                if test.error == "" {
 
132
                        c.Check(err, gc.IsNil)
 
133
                        var units []string
 
134
                        for _, unit := range result {
 
135
                                units = append(units, unit.Name())
 
136
                        }
 
137
                        c.Check(units, jc.SameContents, test.expected)
 
138
                } else {
 
139
                        c.Check(err, gc.ErrorMatches, test.error)
 
140
                }
 
141
        }
 
142
}
 
143
 
 
144
func (s *runSuite) mockSSH(c *gc.C, cmd string) {
 
145
        testbin := c.MkDir()
 
146
        fakessh := filepath.Join(testbin, "ssh")
 
147
        newPath := testbin + ":" + os.Getenv("PATH")
 
148
        s.PatchEnvironment("PATH", newPath)
 
149
        err := ioutil.WriteFile(fakessh, []byte(cmd), 0755)
 
150
        c.Assert(err, gc.IsNil)
 
151
}
 
152
 
 
153
func (s *runSuite) TestParallelExecuteErrorsOnBlankHost(c *gc.C) {
 
154
        s.mockSSH(c, echoInputShowArgs)
 
155
 
 
156
        params := []*client.RemoteExec{
 
157
                &client.RemoteExec{
 
158
                        ExecParams: ssh.ExecParams{
 
159
                                Command: "foo",
 
160
                                Timeout: testing.LongWait,
 
161
                        },
 
162
                },
 
163
        }
 
164
 
 
165
        runResults := client.ParallelExecute("/some/dir", params)
 
166
        c.Assert(runResults.Results, gc.HasLen, 1)
 
167
        result := runResults.Results[0]
 
168
        c.Assert(result.Error, gc.Equals, "missing host address")
 
169
}
 
170
 
 
171
func (s *runSuite) TestParallelExecuteAddsIdentity(c *gc.C) {
 
172
        s.mockSSH(c, echoInputShowArgs)
 
173
 
 
174
        params := []*client.RemoteExec{
 
175
                &client.RemoteExec{
 
176
                        ExecParams: ssh.ExecParams{
 
177
                                Host:    "localhost",
 
178
                                Command: "foo",
 
179
                                Timeout: testing.LongWait,
 
180
                        },
 
181
                },
 
182
        }
 
183
 
 
184
        runResults := client.ParallelExecute("/some/dir", params)
 
185
        c.Assert(runResults.Results, gc.HasLen, 1)
 
186
        result := runResults.Results[0]
 
187
        c.Assert(result.Error, gc.Equals, "")
 
188
        c.Assert(string(result.Stderr), jc.Contains, "-i /some/dir/system-identity")
 
189
}
 
190
 
 
191
func (s *runSuite) TestParallelExecuteCopiesAcrossMachineAndUnit(c *gc.C) {
 
192
        s.mockSSH(c, echoInputShowArgs)
 
193
 
 
194
        params := []*client.RemoteExec{
 
195
                &client.RemoteExec{
 
196
                        ExecParams: ssh.ExecParams{
 
197
                                Host:    "localhost",
 
198
                                Command: "foo",
 
199
                                Timeout: testing.LongWait,
 
200
                        },
 
201
                        MachineId: "machine-id",
 
202
                        UnitId:    "unit-id",
 
203
                },
 
204
        }
 
205
 
 
206
        runResults := client.ParallelExecute("/some/dir", params)
 
207
        c.Assert(runResults.Results, gc.HasLen, 1)
 
208
        result := runResults.Results[0]
 
209
        c.Assert(result.Error, gc.Equals, "")
 
210
        c.Assert(result.MachineId, gc.Equals, "machine-id")
 
211
        c.Assert(result.UnitId, gc.Equals, "unit-id")
 
212
}
 
213
 
 
214
func (s *runSuite) TestRunOnAllMachines(c *gc.C) {
 
215
        // Make three machines.
 
216
        s.addMachineWithAddress(c, "10.3.2.1")
 
217
        s.addMachineWithAddress(c, "10.3.2.2")
 
218
        s.addMachineWithAddress(c, "10.3.2.3")
 
219
 
 
220
        s.mockSSH(c, echoInput)
 
221
 
 
222
        // hmm... this seems to be going through the api client, and from there
 
223
        // through to the apiserver implementation. Not ideal, but it is how the
 
224
        // other client tests are written.
 
225
        client := s.APIState.Client()
 
226
        results, err := client.RunOnAllMachines("hostname", testing.LongWait)
 
227
        c.Assert(err, gc.IsNil)
 
228
        c.Assert(results, gc.HasLen, 3)
 
229
        var expectedResults []params.RunResult
 
230
        for i := 0; i < 3; i++ {
 
231
                expectedResults = append(expectedResults,
 
232
                        params.RunResult{
 
233
                                ExecResponse: exec.ExecResponse{Stdout: []byte("juju-run --no-context 'hostname'\n")},
 
234
                                MachineId:    fmt.Sprint(i),
 
235
                        })
 
236
        }
 
237
 
 
238
        c.Assert(results, jc.DeepEquals, expectedResults)
 
239
}
 
240
 
 
241
func (s *runSuite) TestRunMachineAndService(c *gc.C) {
 
242
        // Make three machines.
 
243
        s.addMachineWithAddress(c, "10.3.2.1")
 
244
 
 
245
        charm := s.AddTestingCharm(c, "dummy")
 
246
        magic, err := s.State.AddService("magic", "user-admin", charm)
 
247
        s.addUnit(c, magic)
 
248
        s.addUnit(c, magic)
 
249
 
 
250
        s.mockSSH(c, echoInput)
 
251
 
 
252
        // hmm... this seems to be going through the api client, and from there
 
253
        // through to the apiserver implementation. Not ideal, but it is how the
 
254
        // other client tests are written.
 
255
        client := s.APIState.Client()
 
256
        results, err := client.Run(
 
257
                params.RunParams{
 
258
                        Commands: "hostname",
 
259
                        Timeout:  testing.LongWait,
 
260
                        Machines: []string{"0"},
 
261
                        Services: []string{"magic"},
 
262
                })
 
263
        c.Assert(err, gc.IsNil)
 
264
        c.Assert(results, gc.HasLen, 3)
 
265
        expectedResults := []params.RunResult{
 
266
                params.RunResult{
 
267
                        ExecResponse: exec.ExecResponse{Stdout: []byte("[ -f \"$HOME/.juju-proxy\" ] && . \"$HOME/.juju-proxy\"\njuju-run --no-context 'hostname'\n")},
 
268
                        MachineId:    "0",
 
269
                },
 
270
                params.RunResult{
 
271
                        ExecResponse: exec.ExecResponse{Stdout: []byte("juju-run magic/0 'hostname'\n")},
 
272
                        MachineId:    "1",
 
273
                        UnitId:       "magic/0",
 
274
                },
 
275
                params.RunResult{
 
276
                        ExecResponse: exec.ExecResponse{Stdout: []byte("juju-run magic/1 'hostname'\n")},
 
277
                        MachineId:    "2",
 
278
                        UnitId:       "magic/1",
 
279
                },
 
280
        }
 
281
 
 
282
        c.Assert(results, jc.DeepEquals, expectedResults)
 
283
}
 
284
 
 
285
var echoInputShowArgs = `#!/bin/bash
 
286
# Write the args to stderr
 
287
echo "$*" >&2
 
288
# And echo stdin to stdout
 
289
while read line
 
290
do echo $line
 
291
done <&0
 
292
`
 
293
 
 
294
var echoInput = `#!/bin/bash
 
295
# And echo stdin to stdout
 
296
while read line
 
297
do echo $line
 
298
done <&0
 
299
`