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  }