~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/cmd/juju/storage/volumelist_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 storage_test
 
5
 
 
6
import (
 
7
        "encoding/json"
 
8
        "time"
 
9
 
 
10
        "github.com/juju/cmd"
 
11
        "github.com/juju/errors"
 
12
        jc "github.com/juju/testing/checkers"
 
13
        gc "gopkg.in/check.v1"
 
14
        goyaml "gopkg.in/yaml.v2"
 
15
 
 
16
        "github.com/juju/juju/apiserver/params"
 
17
        "github.com/juju/juju/cmd/juju/storage"
 
18
        "github.com/juju/juju/status"
 
19
        "github.com/juju/juju/testing"
 
20
)
 
21
 
 
22
func (s *ListSuite) TestVolumeListEmpty(c *gc.C) {
 
23
        s.mockAPI.listVolumes = func([]string) ([]params.VolumeDetailsListResult, error) {
 
24
                return nil, nil
 
25
        }
 
26
        s.assertValidVolumeList(
 
27
                c,
 
28
                []string{"--format", "yaml"},
 
29
                "",
 
30
        )
 
31
}
 
32
 
 
33
func (s *ListSuite) TestVolumeListError(c *gc.C) {
 
34
        s.mockAPI.listVolumes = func([]string) ([]params.VolumeDetailsListResult, error) {
 
35
                return nil, errors.New("just my luck")
 
36
        }
 
37
        context, err := s.runVolumeList(c, "--format", "yaml")
 
38
        c.Assert(errors.Cause(err), gc.ErrorMatches, "just my luck")
 
39
        s.assertUserFacingVolumeOutput(c, context, "", "")
 
40
}
 
41
 
 
42
func (s *ListSuite) TestVolumeListArgs(c *gc.C) {
 
43
        var called bool
 
44
        expectedArgs := []string{"a", "b", "c"}
 
45
        s.mockAPI.listVolumes = func(arg []string) ([]params.VolumeDetailsListResult, error) {
 
46
                c.Assert(arg, jc.DeepEquals, expectedArgs)
 
47
                called = true
 
48
                return nil, nil
 
49
        }
 
50
        s.assertValidVolumeList(
 
51
                c,
 
52
                append([]string{"--format", "yaml"}, expectedArgs...),
 
53
                "",
 
54
        )
 
55
        c.Assert(called, jc.IsTrue)
 
56
}
 
57
 
 
58
func (s *ListSuite) TestVolumeListYaml(c *gc.C) {
 
59
        s.assertUnmarshalledVolumeOutput(
 
60
                c,
 
61
                goyaml.Unmarshal,
 
62
                "", // no error
 
63
                "--format", "yaml")
 
64
}
 
65
 
 
66
func (s *ListSuite) TestVolumeListJSON(c *gc.C) {
 
67
        s.assertUnmarshalledVolumeOutput(
 
68
                c,
 
69
                json.Unmarshal,
 
70
                "", // no error
 
71
                "--format", "json")
 
72
}
 
73
 
 
74
func (s *ListSuite) TestVolumeListWithErrorResults(c *gc.C) {
 
75
        s.mockAPI.listVolumes = func([]string) ([]params.VolumeDetailsListResult, error) {
 
76
                results, _ := mockListAPI{}.ListVolumes(nil)
 
77
                results = append(results, params.VolumeDetailsListResult{
 
78
                        Error: &params.Error{Message: "bad"},
 
79
                })
 
80
                results = append(results, params.VolumeDetailsListResult{
 
81
                        Error: &params.Error{Message: "ness"},
 
82
                })
 
83
                return results, nil
 
84
        }
 
85
        // we should see the error in stderr, but it should not
 
86
        // otherwise affect the rendering of valid results.
 
87
        s.assertUnmarshalledVolumeOutput(c, json.Unmarshal, "bad\nness\n", "--format", "json")
 
88
        s.assertUnmarshalledVolumeOutput(c, goyaml.Unmarshal, "bad\nness\n", "--format", "yaml")
 
89
}
 
90
 
 
91
var expectedVolumeListTabular = `
 
92
MACHINE  UNIT         STORAGE      ID   PROVIDER-ID                   DEVICE  SIZE    STATE      MESSAGE
 
93
0        abc/0        db-dir/1001  0/0  provider-supplied-volume-0-0  loop0   512MiB  attached   
 
94
0        transcode/0  shared-fs/0  4    provider-supplied-volume-4    xvdf2   1.0GiB  attached   
 
95
0                                  1    provider-supplied-volume-1            2.0GiB  attaching  failed to attach, will retry
 
96
1        transcode/1  shared-fs/0  4    provider-supplied-volume-4    xvdf3   1.0GiB  attached   
 
97
1                                  2    provider-supplied-volume-2    xvdf1   3.0MiB  attached   
 
98
1                                  3                                          42MiB   pending    
 
99
 
 
100
`[1:]
 
101
 
 
102
func (s *ListSuite) TestVolumeListTabular(c *gc.C) {
 
103
        s.assertValidVolumeList(c, []string{}, expectedVolumeListTabular)
 
104
 
 
105
        // Do it again, reversing the results returned by the API.
 
106
        // We should get everything sorted in the appropriate order.
 
107
        s.mockAPI.listVolumes = func([]string) ([]params.VolumeDetailsListResult, error) {
 
108
                results, _ := mockListAPI{}.ListVolumes(nil)
 
109
                n := len(results)
 
110
                for i := 0; i < n/2; i++ {
 
111
                        results[i], results[n-i-1] = results[n-i-1], results[i]
 
112
                }
 
113
                return results, nil
 
114
        }
 
115
        s.assertValidVolumeList(c, []string{}, expectedVolumeListTabular)
 
116
}
 
117
 
 
118
func (s *ListSuite) assertUnmarshalledVolumeOutput(c *gc.C, unmarshal unmarshaller, expectedErr string, args ...string) {
 
119
        context, err := s.runVolumeList(c, args...)
 
120
        c.Assert(err, jc.ErrorIsNil)
 
121
 
 
122
        var result struct {
 
123
                Volumes map[string]storage.VolumeInfo
 
124
        }
 
125
        err = unmarshal([]byte(testing.Stdout(context)), &result)
 
126
        c.Assert(err, jc.ErrorIsNil)
 
127
 
 
128
        expected := s.expectVolume(c, nil)
 
129
        c.Assert(result.Volumes, jc.DeepEquals, expected)
 
130
 
 
131
        obtainedErr := testing.Stderr(context)
 
132
        c.Assert(obtainedErr, gc.Equals, expectedErr)
 
133
}
 
134
 
 
135
// expect returns the VolumeInfo mapping we should expect to unmarshal
 
136
// from rendered YAML or JSON.
 
137
func (s *ListSuite) expectVolume(c *gc.C, machines []string) map[string]storage.VolumeInfo {
 
138
        all, err := s.mockAPI.ListVolumes(machines)
 
139
        c.Assert(err, jc.ErrorIsNil)
 
140
 
 
141
        var valid []params.VolumeDetails
 
142
        for _, result := range all {
 
143
                if result.Error == nil {
 
144
                        valid = append(valid, result.Result...)
 
145
                }
 
146
        }
 
147
        result, err := storage.ConvertToVolumeInfo(valid)
 
148
        c.Assert(err, jc.ErrorIsNil)
 
149
        return result
 
150
}
 
151
 
 
152
func (s *ListSuite) assertValidVolumeList(c *gc.C, args []string, expectedOut string) {
 
153
        context, err := s.runVolumeList(c, args...)
 
154
        c.Assert(err, jc.ErrorIsNil)
 
155
        s.assertUserFacingVolumeOutput(c, context, expectedOut, "")
 
156
}
 
157
 
 
158
func (s *ListSuite) runVolumeList(c *gc.C, args ...string) (*cmd.Context, error) {
 
159
        return testing.RunCommand(c,
 
160
                storage.NewListCommandForTest(s.mockAPI, s.store), append(args, "--volume")...)
 
161
}
 
162
 
 
163
func (s *ListSuite) assertUserFacingVolumeOutput(c *gc.C, context *cmd.Context, expectedOut, expectedErr string) {
 
164
        obtainedOut := testing.Stdout(context)
 
165
        c.Assert(obtainedOut, gc.Equals, expectedOut)
 
166
 
 
167
        obtainedErr := testing.Stderr(context)
 
168
        c.Assert(obtainedErr, gc.Equals, expectedErr)
 
169
}
 
170
 
 
171
func (s mockListAPI) ListVolumes(machines []string) ([]params.VolumeDetailsListResult, error) {
 
172
        if s.listVolumes != nil {
 
173
                return s.listVolumes(machines)
 
174
        }
 
175
        results := []params.VolumeDetailsListResult{{Result: []params.VolumeDetails{
 
176
                // volume 0/0 is attached to machine 0, assigned to
 
177
                // storage db-dir/1001, which is attached to unit
 
178
                // abc/0.
 
179
                {
 
180
                        VolumeTag: "volume-0-0",
 
181
                        Info: params.VolumeInfo{
 
182
                                VolumeId: "provider-supplied-volume-0-0",
 
183
                                Size:     512,
 
184
                        },
 
185
                        Status: createTestStatus(status.StatusAttached, ""),
 
186
                        MachineAttachments: map[string]params.VolumeAttachmentInfo{
 
187
                                "machine-0": params.VolumeAttachmentInfo{
 
188
                                        DeviceName: "loop0",
 
189
                                },
 
190
                        },
 
191
                        Storage: &params.StorageDetails{
 
192
                                StorageTag: "storage-db-dir-1001",
 
193
                                OwnerTag:   "unit-abc-0",
 
194
                                Kind:       params.StorageKindBlock,
 
195
                                Status:     createTestStatus(status.StatusAttached, ""),
 
196
                                Attachments: map[string]params.StorageAttachmentDetails{
 
197
                                        "unit-abc-0": params.StorageAttachmentDetails{
 
198
                                                StorageTag: "storage-db-dir-1001",
 
199
                                                UnitTag:    "unit-abc-0",
 
200
                                                MachineTag: "machine-0",
 
201
                                                Location:   "/dev/loop0",
 
202
                                        },
 
203
                                },
 
204
                        },
 
205
                },
 
206
                // volume 1 is attaching to machine 0, but is not assigned
 
207
                // to any storage.
 
208
                {
 
209
                        VolumeTag: "volume-1",
 
210
                        Info: params.VolumeInfo{
 
211
                                VolumeId:   "provider-supplied-volume-1",
 
212
                                HardwareId: "serial blah blah",
 
213
                                Persistent: true,
 
214
                                Size:       2048,
 
215
                        },
 
216
                        Status: createTestStatus(status.StatusAttaching, "failed to attach, will retry"),
 
217
                        MachineAttachments: map[string]params.VolumeAttachmentInfo{
 
218
                                "machine-0": params.VolumeAttachmentInfo{},
 
219
                        },
 
220
                },
 
221
                // volume 3 is due to be attached to machine 1, but is not
 
222
                // assigned to any storage and has not yet been provisioned.
 
223
                {
 
224
                        VolumeTag: "volume-3",
 
225
                        Info: params.VolumeInfo{
 
226
                                Size: 42,
 
227
                        },
 
228
                        Status: createTestStatus(status.StatusPending, ""),
 
229
                        MachineAttachments: map[string]params.VolumeAttachmentInfo{
 
230
                                "machine-1": params.VolumeAttachmentInfo{},
 
231
                        },
 
232
                },
 
233
                // volume 2 is due to be attached to machine 1, but is not
 
234
                // assigned to any storage and has not yet been provisioned.
 
235
                {
 
236
                        VolumeTag: "volume-2",
 
237
                        Info: params.VolumeInfo{
 
238
                                VolumeId: "provider-supplied-volume-2",
 
239
                                Size:     3,
 
240
                        },
 
241
                        Status: createTestStatus(status.StatusAttached, ""),
 
242
                        MachineAttachments: map[string]params.VolumeAttachmentInfo{
 
243
                                "machine-1": params.VolumeAttachmentInfo{
 
244
                                        DeviceName: "xvdf1",
 
245
                                },
 
246
                        },
 
247
                },
 
248
                // volume 4 is attached to machines 0 and 1, and is assigned
 
249
                // to shared storage.
 
250
                {
 
251
                        VolumeTag: "volume-4",
 
252
                        Info: params.VolumeInfo{
 
253
                                VolumeId:   "provider-supplied-volume-4",
 
254
                                Persistent: true,
 
255
                                Size:       1024,
 
256
                        },
 
257
                        Status: createTestStatus(status.StatusAttached, ""),
 
258
                        MachineAttachments: map[string]params.VolumeAttachmentInfo{
 
259
                                "machine-0": params.VolumeAttachmentInfo{
 
260
                                        DeviceName: "xvdf2",
 
261
                                        ReadOnly:   true,
 
262
                                },
 
263
                                "machine-1": params.VolumeAttachmentInfo{
 
264
                                        DeviceName: "xvdf3",
 
265
                                        ReadOnly:   true,
 
266
                                },
 
267
                        },
 
268
                        Storage: &params.StorageDetails{
 
269
                                StorageTag: "storage-shared-fs-0",
 
270
                                OwnerTag:   "application-transcode",
 
271
                                Kind:       params.StorageKindBlock,
 
272
                                Status:     createTestStatus(status.StatusAttached, ""),
 
273
                                Attachments: map[string]params.StorageAttachmentDetails{
 
274
                                        "unit-transcode-0": params.StorageAttachmentDetails{
 
275
                                                StorageTag: "storage-shared-fs-0",
 
276
                                                UnitTag:    "unit-transcode-0",
 
277
                                                MachineTag: "machine-0",
 
278
                                                Location:   "/mnt/bits",
 
279
                                        },
 
280
                                        "unit-transcode-1": params.StorageAttachmentDetails{
 
281
                                                StorageTag: "storage-shared-fs-0",
 
282
                                                UnitTag:    "unit-transcode-1",
 
283
                                                MachineTag: "machine-1",
 
284
                                                Location:   "/mnt/pieces",
 
285
                                        },
 
286
                                },
 
287
                        },
 
288
                },
 
289
        }}}
 
290
        return results, nil
 
291
}
 
292
 
 
293
func createTestStatus(testStatus status.Status, message string) params.EntityStatus {
 
294
        return params.EntityStatus{
 
295
                Status: testStatus,
 
296
                Info:   message,
 
297
                Since:  &time.Time{},
 
298
        }
 
299
}