github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/storage/list_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storage_test 5 6 import ( 7 "errors" 8 "fmt" 9 "time" 10 11 "github.com/juju/cmd" 12 "github.com/juju/cmd/cmdtesting" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/cmd/juju/common" 18 "github.com/juju/juju/cmd/juju/storage" 19 "github.com/juju/juju/core/status" 20 _ "github.com/juju/juju/provider/dummy" 21 ) 22 23 type ListSuite struct { 24 SubStorageSuite 25 mockAPI *mockListAPI 26 } 27 28 var _ = gc.Suite(&ListSuite{}) 29 30 func (s *ListSuite) SetUpTest(c *gc.C) { 31 s.SubStorageSuite.SetUpTest(c) 32 33 s.mockAPI = &mockListAPI{} 34 } 35 36 func (s *ListSuite) runList(c *gc.C, args []string) (*cmd.Context, error) { 37 return cmdtesting.RunCommand(c, storage.NewListCommandForTest(s.mockAPI, s.store), args...) 38 } 39 40 func (s *ListSuite) TestList(c *gc.C) { 41 s.assertValidList( 42 c, 43 nil, 44 // Default format is tabular 45 ` 46 Unit Storage id Type Pool Size Status Message 47 persistent/1 filesystem detached 48 postgresql/0 db-dir/1100 block 3.0MiB attached 49 transcode/0 db-dir/1000 block pending creating volume 50 transcode/0 shared-fs/0 filesystem radiance 1.0GiB attached 51 transcode/1 shared-fs/0 filesystem radiance 1.0GiB attached 52 53 `[1:]) 54 } 55 56 func (s *ListSuite) TestListNoPool(c *gc.C) { 57 s.mockAPI.omitPool = true 58 s.assertValidList( 59 c, 60 nil, 61 // Default format is tabular 62 ` 63 Unit Storage id Type Size Status Message 64 persistent/1 filesystem detached 65 postgresql/0 db-dir/1100 block 3.0MiB attached 66 transcode/0 db-dir/1000 block pending creating volume 67 transcode/0 shared-fs/0 filesystem 1.0GiB attached 68 transcode/1 shared-fs/0 filesystem 1.0GiB attached 69 70 `[1:]) 71 } 72 73 func (s *ListSuite) TestListYAML(c *gc.C) { 74 now := time.Now() 75 s.mockAPI.time = now 76 since := common.FormatTime(&now, false) 77 78 s.assertValidList( 79 c, 80 []string{"--format", "yaml"}, 81 fmt.Sprintf(` 82 storage: 83 db-dir/1000: 84 kind: block 85 status: 86 current: pending 87 message: creating volume 88 since: %s 89 persistent: false 90 attachments: 91 units: 92 transcode/0: 93 location: thither 94 db-dir/1100: 95 kind: block 96 life: dying 97 status: 98 current: attached 99 since: %s 100 persistent: true 101 attachments: 102 units: 103 postgresql/0: 104 location: hither 105 life: dying 106 persistent/1: 107 kind: filesystem 108 status: 109 current: detached 110 since: %s 111 persistent: true 112 shared-fs/0: 113 kind: filesystem 114 status: 115 current: attached 116 since: %s 117 persistent: true 118 attachments: 119 units: 120 transcode/0: 121 location: there 122 transcode/1: 123 location: here 124 filesystems: 125 0/0: 126 provider-id: provider-supplied-filesystem-0-0 127 volume: 0/1 128 storage: db-dir/1001 129 attachments: 130 machines: 131 "0": 132 mount-point: /mnt/fuji 133 read-only: false 134 life: alive 135 units: 136 abc/0: 137 machine: "0" 138 location: /mnt/fuji 139 size: 512 140 life: alive 141 status: 142 current: attached 143 since: %s 144 "1": 145 provider-id: provider-supplied-filesystem-1 146 attachments: 147 machines: 148 "0": 149 mount-point: "" 150 read-only: false 151 size: 2048 152 status: 153 current: attaching 154 message: failed to attach, will retry 155 since: %s 156 "2": 157 provider-id: provider-supplied-filesystem-2 158 attachments: 159 machines: 160 "1": 161 mount-point: /mnt/zion 162 read-only: false 163 size: 3 164 status: 165 current: attached 166 since: %s 167 "3": 168 attachments: 169 machines: 170 "1": 171 mount-point: "" 172 read-only: false 173 size: 42 174 status: 175 current: pending 176 since: %s 177 "4": 178 provider-id: provider-supplied-filesystem-4 179 storage: shared-fs/0 180 attachments: 181 machines: 182 "0": 183 mount-point: /mnt/doom 184 read-only: true 185 "1": 186 mount-point: /mnt/huang 187 read-only: true 188 units: 189 transcode/0: 190 machine: "0" 191 location: /mnt/bits 192 transcode/1: 193 machine: "1" 194 location: /mnt/pieces 195 pool: radiance 196 size: 1024 197 status: 198 current: attached 199 since: %s 200 "5": 201 provider-id: provider-supplied-filesystem-5 202 storage: db-dir/1100 203 attachments: 204 units: 205 abc/0: 206 location: /mnt/fuji 207 size: 3 208 status: 209 current: attached 210 since: %s 211 volumes: 212 0/0: 213 provider-id: provider-supplied-volume-0-0 214 storage: db-dir/1001 215 attachments: 216 machines: 217 "0": 218 device: loop0 219 read-only: false 220 life: alive 221 units: 222 abc/0: 223 machine: "0" 224 location: /dev/loop0 225 pool: radiance 226 size: 512 227 persistent: false 228 life: alive 229 status: 230 current: attached 231 since: %s 232 "1": 233 provider-id: provider-supplied-volume-1 234 attachments: 235 machines: 236 "0": 237 read-only: false 238 hardware-id: serial blah blah 239 size: 2048 240 persistent: true 241 status: 242 current: attaching 243 message: failed to attach, will retry 244 since: %s 245 "2": 246 provider-id: provider-supplied-volume-2 247 attachments: 248 machines: 249 "1": 250 device: xvdf1 251 read-only: false 252 size: 3 253 persistent: false 254 status: 255 current: attached 256 since: %s 257 "3": 258 attachments: 259 machines: 260 "1": 261 read-only: false 262 size: 42 263 persistent: false 264 status: 265 current: pending 266 since: %s 267 "4": 268 provider-id: provider-supplied-volume-4 269 storage: shared-fs/0 270 attachments: 271 machines: 272 "0": 273 device: xvdf2 274 read-only: true 275 "1": 276 device: xvdf3 277 read-only: true 278 units: 279 transcode/0: 280 machine: "0" 281 location: /mnt/bits 282 transcode/1: 283 machine: "1" 284 location: /mnt/pieces 285 size: 1024 286 persistent: true 287 status: 288 current: attached 289 since: %s 290 `[1:], repeat(since, 15)...)) 291 } 292 293 func (s *ListSuite) TestListInitErrors(c *gc.C) { 294 s.testListInitError(c, []string{"--filesystem", "--volume"}, "--filesystem and --volume can not be used together") 295 s.testListInitError(c, []string{"storage-id"}, "specifying IDs only supported with --filesystem and --volume options") 296 } 297 298 func (s *ListSuite) testListInitError(c *gc.C, args []string, expectedErr string) { 299 _, err := s.runList(c, args) 300 c.Assert(err, gc.ErrorMatches, expectedErr) 301 } 302 303 func (s *ListSuite) TestListError(c *gc.C) { 304 s.mockAPI.listErrors = true 305 context, err := s.runList(c, nil) 306 c.Assert(err, gc.ErrorMatches, "list fails") 307 stderr := cmdtesting.Stderr(context) 308 c.Assert(stderr, gc.Equals, "") 309 stdout := cmdtesting.Stdout(context) 310 c.Assert(stdout, gc.Equals, "") 311 } 312 313 func (s *ListSuite) assertValidList(c *gc.C, args []string, expectedValid string) { 314 context, err := s.runList(c, args) 315 c.Assert(err, jc.ErrorIsNil) 316 317 obtainedErr := cmdtesting.Stderr(context) 318 c.Assert(obtainedErr, gc.Equals, "") 319 320 obtainedValid := cmdtesting.Stdout(context) 321 c.Assert(obtainedValid, gc.Equals, expectedValid) 322 } 323 324 type mockListAPI struct { 325 listErrors bool 326 listFilesystems func([]string) ([]params.FilesystemDetailsListResult, error) 327 listVolumes func([]string) ([]params.VolumeDetailsListResult, error) 328 omitPool bool 329 time time.Time 330 } 331 332 func (s *mockListAPI) Close() error { 333 return nil 334 } 335 336 func (s *mockListAPI) ListStorageDetails() ([]params.StorageDetails, error) { 337 if s.listErrors { 338 return nil, errors.New("list fails") 339 } 340 341 // postgresql/0 has "db-dir/1100" 342 // transcode/1 has "db-dir/1000" 343 // transcode/0 and transcode/1 share "shared-fs/0" 344 // 345 // there is also a storage instance "db-dir/1010" which 346 // returns an error when listed. 347 results := []params.StorageDetails{{ 348 StorageTag: "storage-db-dir-1000", 349 OwnerTag: "unit-transcode-0", 350 Kind: params.StorageKindBlock, 351 Status: params.EntityStatus{ 352 Status: status.Pending, 353 Since: &s.time, 354 Info: "creating volume", 355 }, 356 Attachments: map[string]params.StorageAttachmentDetails{ 357 "unit-transcode-0": { 358 Location: "thither", 359 }, 360 }, 361 }, { 362 StorageTag: "storage-db-dir-1100", 363 OwnerTag: "unit-postgresql-0", 364 Kind: params.StorageKindBlock, 365 Life: "dying", 366 Status: params.EntityStatus{ 367 Status: status.Attached, 368 Since: &s.time, 369 }, 370 Persistent: true, 371 Attachments: map[string]params.StorageAttachmentDetails{ 372 "unit-postgresql-0": { 373 Location: "hither", 374 Life: "dying", 375 }, 376 }, 377 }, { 378 StorageTag: "storage-shared-fs-0", 379 OwnerTag: "application-transcode", 380 Kind: params.StorageKindFilesystem, 381 Status: params.EntityStatus{ 382 Status: status.Attached, 383 Since: &s.time, 384 }, 385 Persistent: true, 386 Attachments: map[string]params.StorageAttachmentDetails{ 387 "unit-transcode-0": { 388 Location: "there", 389 }, 390 "unit-transcode-1": { 391 Location: "here", 392 }, 393 }, 394 }, { 395 StorageTag: "storage-persistent-1", 396 Kind: params.StorageKindFilesystem, 397 Status: params.EntityStatus{ 398 Status: status.Detached, 399 Since: &s.time, 400 }, 401 Persistent: true, 402 }} 403 return results, nil 404 } 405 406 // repeat is used for duplicating the string multiple times. 407 func repeat(s string, amount int) []interface{} { 408 var a []interface{} 409 for i := 0; i < amount; i++ { 410 a = append(a, s) 411 } 412 return a 413 }