github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/api/storage/client_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  	"fmt"
     8  
     9  	"github.com/juju/collections/set"
    10  	"github.com/juju/errors"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  	"gopkg.in/juju/names.v2"
    14  
    15  	basetesting "github.com/juju/juju/api/base/testing"
    16  	"github.com/juju/juju/api/storage"
    17  	"github.com/juju/juju/apiserver/common"
    18  	"github.com/juju/juju/apiserver/params"
    19  	jujustorage "github.com/juju/juju/storage"
    20  	"github.com/juju/juju/testing"
    21  )
    22  
    23  type storageMockSuite struct {
    24  	testing.BaseSuite
    25  }
    26  
    27  var _ = gc.Suite(&storageMockSuite{})
    28  
    29  func (s *storageMockSuite) TestStorageDetails(c *gc.C) {
    30  	one := "shared-fs/0"
    31  	oneTag := names.NewStorageTag(one)
    32  	two := "db-dir/1000"
    33  	twoTag := names.NewStorageTag(two)
    34  	expected := set.NewStrings(oneTag.String(), twoTag.String())
    35  	msg := "call failure"
    36  
    37  	apiCaller := basetesting.APICallerFunc(
    38  		func(objType string,
    39  			version int,
    40  			id, request string,
    41  			a, result interface{},
    42  		) error {
    43  			c.Check(objType, gc.Equals, "Storage")
    44  			c.Check(id, gc.Equals, "")
    45  			c.Check(request, gc.Equals, "StorageDetails")
    46  
    47  			args, ok := a.(params.Entities)
    48  			c.Assert(ok, jc.IsTrue)
    49  			c.Assert(args.Entities, gc.HasLen, 2)
    50  
    51  			if results, k := result.(*params.StorageDetailsResults); k {
    52  				instances := []params.StorageDetailsResult{
    53  					{
    54  						Result: &params.StorageDetails{StorageTag: oneTag.String()},
    55  					},
    56  					{
    57  						Result: &params.StorageDetails{
    58  							StorageTag: twoTag.String(),
    59  							Status: params.EntityStatus{
    60  								Status: "attached",
    61  							},
    62  							Persistent: true,
    63  						},
    64  					},
    65  					{
    66  						Error: common.ServerError(errors.New(msg)),
    67  					},
    68  				}
    69  				results.Results = instances
    70  			}
    71  
    72  			return nil
    73  		})
    74  	storageClient := storage.NewClient(apiCaller)
    75  	tags := []names.StorageTag{oneTag, twoTag}
    76  	found, err := storageClient.StorageDetails(tags)
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	c.Assert(found, gc.HasLen, 3)
    79  	c.Assert(expected.Contains(found[0].Result.StorageTag), jc.IsTrue)
    80  	c.Assert(expected.Contains(found[1].Result.StorageTag), jc.IsTrue)
    81  	c.Assert(found[2].Error, gc.ErrorMatches, msg)
    82  }
    83  
    84  func (s *storageMockSuite) TestStorageDetailsFacadeCallError(c *gc.C) {
    85  	one := "shared-fs/0"
    86  	oneTag := names.NewStorageTag(one)
    87  
    88  	msg := "facade failure"
    89  	apiCaller := basetesting.APICallerFunc(
    90  		func(objType string,
    91  			version int,
    92  			id, request string,
    93  			a, result interface{},
    94  		) error {
    95  			c.Check(objType, gc.Equals, "Storage")
    96  			c.Check(id, gc.Equals, "")
    97  			c.Check(request, gc.Equals, "StorageDetails")
    98  
    99  			return errors.New(msg)
   100  		})
   101  	storageClient := storage.NewClient(apiCaller)
   102  	found, err := storageClient.StorageDetails([]names.StorageTag{oneTag})
   103  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   104  	c.Assert(found, gc.HasLen, 0)
   105  }
   106  
   107  func (s *storageMockSuite) TestListStorageDetails(c *gc.C) {
   108  	storageTag := names.NewStorageTag("db-dir/1000")
   109  
   110  	apiCaller := basetesting.APICallerFunc(
   111  		func(objType string,
   112  			version int,
   113  			id, request string,
   114  			a, result interface{},
   115  		) error {
   116  			c.Check(objType, gc.Equals, "Storage")
   117  			c.Check(id, gc.Equals, "")
   118  			c.Check(request, gc.Equals, "ListStorageDetails")
   119  			c.Check(a, jc.DeepEquals, params.StorageFilters{
   120  				[]params.StorageFilter{{}},
   121  			})
   122  
   123  			c.Assert(result, gc.FitsTypeOf, &params.StorageDetailsListResults{})
   124  			results := result.(*params.StorageDetailsListResults)
   125  			results.Results = []params.StorageDetailsListResult{{
   126  				Result: []params.StorageDetails{{
   127  					StorageTag: storageTag.String(),
   128  					Status: params.EntityStatus{
   129  						Status: "attached",
   130  					},
   131  					Persistent: true,
   132  				}},
   133  			}}
   134  
   135  			return nil
   136  		},
   137  	)
   138  	storageClient := storage.NewClient(apiCaller)
   139  	found, err := storageClient.ListStorageDetails()
   140  	c.Check(err, jc.ErrorIsNil)
   141  	c.Assert(found, gc.HasLen, 1)
   142  	expected := []params.StorageDetails{{
   143  		StorageTag: "storage-db-dir-1000",
   144  		Status: params.EntityStatus{
   145  			Status: "attached",
   146  		},
   147  		Persistent: true,
   148  	}}
   149  
   150  	c.Assert(found, jc.DeepEquals, expected)
   151  }
   152  
   153  func (s *storageMockSuite) TestListStorageDetailsFacadeCallError(c *gc.C) {
   154  	msg := "facade failure"
   155  	apiCaller := basetesting.APICallerFunc(
   156  		func(objType string,
   157  			version int,
   158  			id, request string,
   159  			a, result interface{},
   160  		) error {
   161  			c.Check(objType, gc.Equals, "Storage")
   162  			c.Check(id, gc.Equals, "")
   163  			c.Check(request, gc.Equals, "ListStorageDetails")
   164  
   165  			return errors.New(msg)
   166  		})
   167  	storageClient := storage.NewClient(apiCaller)
   168  	found, err := storageClient.ListStorageDetails()
   169  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   170  	c.Assert(found, gc.HasLen, 0)
   171  }
   172  
   173  func (s *storageMockSuite) TestListPools(c *gc.C) {
   174  	expected := []params.StoragePool{
   175  		{Name: "name0", Provider: "type0"},
   176  		{Name: "name1", Provider: "type1"},
   177  		{Name: "name2", Provider: "type2"},
   178  	}
   179  	want := len(expected)
   180  
   181  	apiCaller := basetesting.APICallerFunc(
   182  		func(objType string,
   183  			version int,
   184  			id, request string,
   185  			a, result interface{},
   186  		) error {
   187  			c.Check(objType, gc.Equals, "Storage")
   188  			c.Check(id, gc.Equals, "")
   189  			c.Check(request, gc.Equals, "ListPools")
   190  
   191  			args := a.(params.StoragePoolFilters)
   192  			c.Assert(args.Filters, gc.HasLen, 1)
   193  			c.Assert(args.Filters[0].Names, gc.HasLen, 2)
   194  			c.Assert(args.Filters[0].Providers, gc.HasLen, 1)
   195  
   196  			results := result.(*params.StoragePoolsResults)
   197  			pools := make([]params.StoragePool, want)
   198  			for i := 0; i < want; i++ {
   199  				pools[i] = params.StoragePool{
   200  					Name:     fmt.Sprintf("name%v", i),
   201  					Provider: fmt.Sprintf("type%v", i),
   202  				}
   203  			}
   204  			results.Results = []params.StoragePoolsResult{{
   205  				Result: pools,
   206  			}}
   207  
   208  			return nil
   209  		})
   210  	storageClient := storage.NewClient(apiCaller)
   211  	names := []string{"a", "b"}
   212  	types := []string{"1"}
   213  	found, err := storageClient.ListPools(types, names)
   214  	c.Assert(err, jc.ErrorIsNil)
   215  	c.Assert(found, gc.HasLen, want)
   216  	c.Assert(found, gc.DeepEquals, expected)
   217  }
   218  
   219  func (s *storageMockSuite) TestListPoolsFacadeCallError(c *gc.C) {
   220  	msg := "facade failure"
   221  	apiCaller := basetesting.APICallerFunc(
   222  		func(objType string,
   223  			version int,
   224  			id, request string,
   225  			a, result interface{},
   226  		) error {
   227  			c.Check(objType, gc.Equals, "Storage")
   228  			c.Check(id, gc.Equals, "")
   229  			c.Check(request, gc.Equals, "ListPools")
   230  
   231  			return errors.New(msg)
   232  		})
   233  	storageClient := storage.NewClient(apiCaller)
   234  	found, err := storageClient.ListPools(nil, nil)
   235  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   236  	c.Assert(found, gc.HasLen, 0)
   237  }
   238  
   239  func (s *storageMockSuite) TestCreatePool(c *gc.C) {
   240  	var called bool
   241  	poolName := "poolName"
   242  	poolType := "poolType"
   243  	poolConfig := map[string]interface{}{
   244  		"test": "one",
   245  		"pass": true,
   246  	}
   247  	apiCaller := basetesting.BestVersionCaller{
   248  		APICallerFunc: basetesting.APICallerFunc(
   249  			func(objType string,
   250  				version int,
   251  				id, request string,
   252  				a, result interface{},
   253  			) error {
   254  				called = true
   255  				c.Check(objType, gc.Equals, "Storage")
   256  				c.Check(id, gc.Equals, "")
   257  				c.Check(request, gc.Equals, "CreatePool")
   258  
   259  				args, ok := a.(params.StoragePoolArgs)
   260  				c.Assert(ok, jc.IsTrue)
   261  				c.Assert(args.Pools, gc.HasLen, 1)
   262  
   263  				c.Assert(args.Pools[0].Name, gc.Equals, poolName)
   264  				c.Assert(args.Pools[0].Provider, gc.Equals, poolType)
   265  				c.Assert(args.Pools[0].Attrs, gc.DeepEquals, poolConfig)
   266  				results := result.(*params.ErrorResults)
   267  
   268  				results.Results = make([]params.ErrorResult, len(args.Pools))
   269  				return nil
   270  			},
   271  		),
   272  		BestVersion: 5,
   273  	}
   274  	storageClient := storage.NewClient(apiCaller)
   275  	err := storageClient.CreatePool(poolName, poolType, poolConfig)
   276  	c.Assert(err, jc.ErrorIsNil)
   277  	c.Assert(called, jc.IsTrue)
   278  }
   279  
   280  func (s *storageMockSuite) TestCreatePoolFacadeCallError(c *gc.C) {
   281  	msg := "facade failure"
   282  	apiCaller := basetesting.APICallerFunc(
   283  		func(objType string,
   284  			version int,
   285  			id, request string,
   286  			a, result interface{},
   287  		) error {
   288  			c.Check(objType, gc.Equals, "Storage")
   289  			c.Check(id, gc.Equals, "")
   290  			c.Check(request, gc.Equals, "CreatePool")
   291  
   292  			return errors.New(msg)
   293  		})
   294  	storageClient := storage.NewClient(apiCaller)
   295  	err := storageClient.CreatePool("", "", nil)
   296  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   297  }
   298  
   299  func (s *storageMockSuite) TestLegacyCreatePool(c *gc.C) {
   300  	var called bool
   301  	poolName := "poolName"
   302  	poolType := "poolType"
   303  	poolConfig := map[string]interface{}{
   304  		"test": "one",
   305  		"pass": true,
   306  	}
   307  
   308  	apiCaller := basetesting.APICallerFunc(
   309  		func(objType string,
   310  			version int,
   311  			id, request string,
   312  			a, result interface{},
   313  		) error {
   314  			called = true
   315  			c.Check(objType, gc.Equals, "Storage")
   316  			c.Check(id, gc.Equals, "")
   317  			c.Check(request, gc.Equals, "CreatePool")
   318  
   319  			args, ok := a.(params.StoragePool)
   320  			c.Assert(ok, jc.IsTrue)
   321  			c.Assert(args.Name, gc.Equals, poolName)
   322  			c.Assert(args.Provider, gc.Equals, poolType)
   323  			c.Assert(args.Attrs, gc.DeepEquals, poolConfig)
   324  
   325  			return nil
   326  		})
   327  	storageClient := storage.NewClient(apiCaller)
   328  	err := storageClient.CreatePool(poolName, poolType, poolConfig)
   329  	c.Assert(err, jc.ErrorIsNil)
   330  	c.Assert(called, jc.IsTrue)
   331  }
   332  
   333  func (s *storageMockSuite) TestLegacyCreatePoolFacadeCallError(c *gc.C) {
   334  	msg := "facade failure"
   335  	apiCaller := basetesting.APICallerFunc(
   336  		func(objType string,
   337  			version int,
   338  			id, request string,
   339  			a, result interface{},
   340  		) error {
   341  			c.Check(objType, gc.Equals, "Storage")
   342  			c.Check(id, gc.Equals, "")
   343  			c.Check(request, gc.Equals, "CreatePool")
   344  
   345  			return errors.New(msg)
   346  		})
   347  	storageClient := storage.NewClient(apiCaller)
   348  	err := storageClient.CreatePool("", "", nil)
   349  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   350  }
   351  
   352  func (s *storageMockSuite) TestListVolumes(c *gc.C) {
   353  	var called bool
   354  	machines := []string{"0", "1"}
   355  	apiCaller := basetesting.APICallerFunc(
   356  		func(objType string,
   357  			version int,
   358  			id, request string,
   359  			a, result interface{},
   360  		) error {
   361  			called = true
   362  			c.Check(objType, gc.Equals, "Storage")
   363  			c.Check(id, gc.Equals, "")
   364  			c.Check(request, gc.Equals, "ListVolumes")
   365  
   366  			c.Assert(a, gc.FitsTypeOf, params.VolumeFilters{})
   367  			args := a.(params.VolumeFilters)
   368  			c.Assert(args.Filters, gc.HasLen, 2)
   369  			c.Assert(args.Filters[0].Machines, jc.DeepEquals, []string{"machine-0"})
   370  			c.Assert(args.Filters[1].Machines, jc.DeepEquals, []string{"machine-1"})
   371  
   372  			c.Assert(result, gc.FitsTypeOf, &params.VolumeDetailsListResults{})
   373  			results := result.(*params.VolumeDetailsListResults)
   374  
   375  			details := params.VolumeDetails{
   376  				VolumeTag: "volume-0",
   377  				MachineAttachments: map[string]params.VolumeAttachmentDetails{
   378  					"machine-0": {},
   379  					"machine-1": {},
   380  				},
   381  			}
   382  			results.Results = []params.VolumeDetailsListResult{{
   383  				Result: []params.VolumeDetails{details},
   384  			}, {
   385  				Result: []params.VolumeDetails{details},
   386  			}}
   387  			return nil
   388  		})
   389  	storageClient := storage.NewClient(apiCaller)
   390  	found, err := storageClient.ListVolumes(machines)
   391  	c.Assert(called, jc.IsTrue)
   392  	c.Assert(err, jc.ErrorIsNil)
   393  	c.Assert(found, gc.HasLen, 2)
   394  	for i := 0; i < 2; i++ {
   395  		c.Assert(found[i].Result, jc.DeepEquals, []params.VolumeDetails{{
   396  			VolumeTag: "volume-0",
   397  			MachineAttachments: map[string]params.VolumeAttachmentDetails{
   398  				"machine-0": {},
   399  				"machine-1": {},
   400  			},
   401  		}})
   402  	}
   403  }
   404  
   405  func (s *storageMockSuite) TestListVolumesEmptyFilter(c *gc.C) {
   406  	var called bool
   407  	tag := "ok"
   408  	apiCaller := basetesting.APICallerFunc(
   409  		func(objType string,
   410  			version int,
   411  			id, request string,
   412  			a, result interface{},
   413  		) error {
   414  			called = true
   415  			c.Check(objType, gc.Equals, "Storage")
   416  			c.Check(id, gc.Equals, "")
   417  			c.Check(request, gc.Equals, "ListVolumes")
   418  
   419  			c.Assert(a, gc.FitsTypeOf, params.VolumeFilters{})
   420  			args := a.(params.VolumeFilters)
   421  			c.Assert(args.Filters, gc.HasLen, 1)
   422  			c.Assert(args.Filters[0].IsEmpty(), jc.IsTrue)
   423  
   424  			c.Assert(result, gc.FitsTypeOf, &params.VolumeDetailsListResults{})
   425  			results := result.(*params.VolumeDetailsListResults)
   426  			results.Results = []params.VolumeDetailsListResult{
   427  				{Result: []params.VolumeDetails{{VolumeTag: tag}}},
   428  			}
   429  			return nil
   430  		},
   431  	)
   432  	storageClient := storage.NewClient(apiCaller)
   433  	found, err := storageClient.ListVolumes(nil)
   434  	c.Assert(called, jc.IsTrue)
   435  	c.Assert(err, jc.ErrorIsNil)
   436  	c.Assert(found, gc.HasLen, 1)
   437  	c.Assert(found[0].Result, gc.HasLen, 1)
   438  	c.Assert(found[0].Result[0].VolumeTag, gc.Equals, tag)
   439  }
   440  
   441  func (s *storageMockSuite) TestListVolumesFacadeCallError(c *gc.C) {
   442  	msg := "facade failure"
   443  	apiCaller := basetesting.APICallerFunc(
   444  		func(objType string,
   445  			version int,
   446  			id, request string,
   447  			a, result interface{},
   448  		) error {
   449  			c.Check(objType, gc.Equals, "Storage")
   450  			c.Check(id, gc.Equals, "")
   451  			c.Check(request, gc.Equals, "ListVolumes")
   452  
   453  			return errors.New(msg)
   454  		})
   455  	storageClient := storage.NewClient(apiCaller)
   456  	_, err := storageClient.ListVolumes(nil)
   457  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   458  }
   459  
   460  func (s *storageMockSuite) TestListFilesystems(c *gc.C) {
   461  	expected := params.FilesystemDetails{
   462  		FilesystemTag: "filesystem-1",
   463  		Info: params.FilesystemInfo{
   464  			FilesystemId: "fs-id",
   465  			Size:         4096,
   466  		},
   467  		Status: params.EntityStatus{
   468  			Status: "attached",
   469  		},
   470  		MachineAttachments: map[string]params.FilesystemAttachmentDetails{
   471  			"0": {
   472  				FilesystemAttachmentInfo: params.FilesystemAttachmentInfo{
   473  					MountPoint: "/mnt/kinabalu",
   474  					ReadOnly:   false,
   475  				},
   476  			},
   477  		},
   478  	}
   479  
   480  	apiCaller := basetesting.APICallerFunc(
   481  		func(objType string,
   482  			version int,
   483  			id, request string,
   484  			a, result interface{},
   485  		) error {
   486  			c.Check(objType, gc.Equals, "Storage")
   487  			c.Check(id, gc.Equals, "")
   488  			c.Check(request, gc.Equals, "ListFilesystems")
   489  
   490  			c.Assert(a, gc.FitsTypeOf, params.FilesystemFilters{})
   491  			args := a.(params.FilesystemFilters)
   492  			c.Assert(args.Filters, jc.DeepEquals, []params.FilesystemFilter{{
   493  				Machines: []string{"machine-1"},
   494  			}, {
   495  				Machines: []string{"machine-2"},
   496  			}})
   497  
   498  			c.Assert(result, gc.FitsTypeOf, &params.FilesystemDetailsListResults{})
   499  			results := result.(*params.FilesystemDetailsListResults)
   500  			results.Results = []params.FilesystemDetailsListResult{{
   501  				Result: []params.FilesystemDetails{expected},
   502  			}, {}}
   503  			return nil
   504  		},
   505  	)
   506  	storageClient := storage.NewClient(apiCaller)
   507  	found, err := storageClient.ListFilesystems([]string{"1", "2"})
   508  	c.Assert(err, jc.ErrorIsNil)
   509  	c.Assert(found, gc.HasLen, 2)
   510  	c.Assert(found[0].Result, jc.DeepEquals, []params.FilesystemDetails{expected})
   511  	c.Assert(found[1].Result, jc.DeepEquals, []params.FilesystemDetails{})
   512  }
   513  
   514  func (s *storageMockSuite) TestListFilesystemsEmptyFilter(c *gc.C) {
   515  	var called bool
   516  	apiCaller := basetesting.APICallerFunc(
   517  		func(objType string,
   518  			version int,
   519  			id, request string,
   520  			a, result interface{},
   521  		) error {
   522  			called = true
   523  			c.Check(objType, gc.Equals, "Storage")
   524  			c.Check(id, gc.Equals, "")
   525  			c.Check(request, gc.Equals, "ListFilesystems")
   526  
   527  			c.Assert(a, gc.FitsTypeOf, params.FilesystemFilters{})
   528  			args := a.(params.FilesystemFilters)
   529  			c.Assert(args.Filters, gc.HasLen, 1)
   530  			c.Assert(args.Filters[0].IsEmpty(), jc.IsTrue)
   531  
   532  			c.Assert(result, gc.FitsTypeOf, &params.FilesystemDetailsListResults{})
   533  			results := result.(*params.FilesystemDetailsListResults)
   534  			results.Results = []params.FilesystemDetailsListResult{{}}
   535  
   536  			return nil
   537  		},
   538  	)
   539  	storageClient := storage.NewClient(apiCaller)
   540  	_, err := storageClient.ListFilesystems(nil)
   541  	c.Assert(called, jc.IsTrue)
   542  	c.Assert(err, jc.ErrorIsNil)
   543  }
   544  
   545  func (s *storageMockSuite) TestListFilesystemsFacadeCallError(c *gc.C) {
   546  	msg := "facade failure"
   547  	apiCaller := basetesting.APICallerFunc(
   548  		func(objType string,
   549  			version int,
   550  			id, request string,
   551  			a, result interface{},
   552  		) error {
   553  			c.Check(objType, gc.Equals, "Storage")
   554  			c.Check(id, gc.Equals, "")
   555  			c.Check(request, gc.Equals, "ListFilesystems")
   556  
   557  			return errors.New(msg)
   558  		})
   559  	storageClient := storage.NewClient(apiCaller)
   560  	_, err := storageClient.ListFilesystems(nil)
   561  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   562  }
   563  
   564  func (s *storageMockSuite) TestAddToUnit(c *gc.C) {
   565  	size := uint64(42)
   566  	cons := params.StorageConstraints{
   567  		Pool: "value",
   568  		Size: &size,
   569  	}
   570  
   571  	errOut := "error"
   572  	unitStorages := []params.StorageAddParams{
   573  		{UnitTag: "u-a", StorageName: "one", Constraints: cons},
   574  		{UnitTag: "u-b", StorageName: errOut, Constraints: cons},
   575  		{UnitTag: "u-b", StorageName: "nil-constraints"},
   576  	}
   577  
   578  	storageN := 3
   579  	expectedError := common.ServerError(errors.NotValidf("storage directive"))
   580  	expectedDetails := &params.AddStorageDetails{[]string{"a/0", "b/1"}}
   581  	one := func(u, s string, attrs params.StorageConstraints) params.AddStorageResult {
   582  		result := params.AddStorageResult{}
   583  		if s == errOut {
   584  			result.Error = expectedError
   585  		} else {
   586  			result.Result = expectedDetails
   587  		}
   588  		return result
   589  	}
   590  
   591  	apiCaller := basetesting.APICallerFunc(
   592  		func(objType string,
   593  			version int,
   594  			id, request string,
   595  			a, result interface{},
   596  		) error {
   597  			c.Check(objType, gc.Equals, "Storage")
   598  			c.Check(id, gc.Equals, "")
   599  			c.Check(request, gc.Equals, "AddToUnit")
   600  
   601  			args, ok := a.(params.StoragesAddParams)
   602  			c.Assert(ok, jc.IsTrue)
   603  			c.Assert(args.Storages, gc.HasLen, storageN)
   604  			c.Assert(args.Storages, gc.DeepEquals, unitStorages)
   605  
   606  			if results, k := result.(*params.AddStorageResults); k {
   607  				out := []params.AddStorageResult{}
   608  				for _, s := range args.Storages {
   609  					out = append(out, one(s.UnitTag, s.StorageName, s.Constraints))
   610  				}
   611  				results.Results = out
   612  			}
   613  
   614  			return nil
   615  		})
   616  	storageClient := storage.NewClient(apiCaller)
   617  	r, err := storageClient.AddToUnit(unitStorages)
   618  	c.Assert(err, jc.ErrorIsNil)
   619  	c.Assert(r, gc.HasLen, storageN)
   620  	expected := []params.AddStorageResult{
   621  		{Result: expectedDetails},
   622  		{Error: expectedError},
   623  		{Result: expectedDetails},
   624  	}
   625  	c.Assert(r, jc.SameContents, expected)
   626  }
   627  
   628  func (s *storageMockSuite) TestAddToUnitFacadeCallError(c *gc.C) {
   629  	unitStorages := []params.StorageAddParams{
   630  		{UnitTag: "u-a", StorageName: "one"},
   631  	}
   632  
   633  	msg := "facade failure"
   634  	apiCaller := basetesting.APICallerFunc(
   635  		func(objType string,
   636  			version int,
   637  			id, request string,
   638  			a, result interface{},
   639  		) error {
   640  			c.Check(objType, gc.Equals, "Storage")
   641  			c.Check(id, gc.Equals, "")
   642  			c.Check(request, gc.Equals, "AddToUnit")
   643  			return errors.New(msg)
   644  		})
   645  	storageClient := storage.NewClient(apiCaller)
   646  	found, err := storageClient.AddToUnit(unitStorages)
   647  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   648  	c.Assert(found, gc.HasLen, 0)
   649  }
   650  
   651  func (s *storageMockSuite) TestRemove(c *gc.C) {
   652  	apiCaller := basetesting.BestVersionCaller{
   653  		APICallerFunc: basetesting.APICallerFunc(
   654  			func(objType string,
   655  				version int,
   656  				id, request string,
   657  				a, result interface{},
   658  			) error {
   659  				c.Check(objType, gc.Equals, "Storage")
   660  				c.Check(id, gc.Equals, "")
   661  				c.Check(request, gc.Equals, "Remove")
   662  				c.Check(a, jc.DeepEquals, params.RemoveStorage{[]params.RemoveStorageInstance{
   663  					{Tag: "storage-foo-0", DestroyAttachments: false, DestroyStorage: false},
   664  					{Tag: "storage-bar-1", DestroyAttachments: false, DestroyStorage: false},
   665  				}})
   666  				c.Assert(result, gc.FitsTypeOf, &params.ErrorResults{})
   667  				results := result.(*params.ErrorResults)
   668  				results.Results = []params.ErrorResult{
   669  					{},
   670  					{Error: &params.Error{Message: "baz"}},
   671  				}
   672  				return nil
   673  			},
   674  		),
   675  		BestVersion: 4,
   676  	}
   677  	client := storage.NewClient(apiCaller)
   678  	results, err := client.Remove([]string{"foo/0", "bar/1"}, false, false)
   679  	c.Check(err, jc.ErrorIsNil)
   680  	c.Assert(results, gc.HasLen, 2)
   681  	c.Assert(results[0].Error, gc.IsNil)
   682  	c.Assert(results[1].Error, jc.DeepEquals, &params.Error{Message: "baz"})
   683  }
   684  
   685  func (s *storageMockSuite) TestRemoveDestroyAttachments(c *gc.C) {
   686  	apiCaller := basetesting.BestVersionCaller{
   687  		APICallerFunc: basetesting.APICallerFunc(
   688  			func(objType string,
   689  				version int,
   690  				id, request string,
   691  				a, result interface{},
   692  			) error {
   693  				c.Check(a, jc.DeepEquals, params.RemoveStorage{[]params.RemoveStorageInstance{{
   694  					Tag:                "storage-foo-0",
   695  					DestroyAttachments: true,
   696  					DestroyStorage:     true,
   697  				}}})
   698  				results := result.(*params.ErrorResults)
   699  				results.Results = []params.ErrorResult{{}}
   700  				return nil
   701  			},
   702  		),
   703  		BestVersion: 4,
   704  	}
   705  	client := storage.NewClient(apiCaller)
   706  	results, err := client.Remove([]string{"foo/0"}, true, true)
   707  	c.Check(err, jc.ErrorIsNil)
   708  	c.Assert(results, gc.HasLen, 1)
   709  	c.Assert(results[0].Error, gc.IsNil)
   710  }
   711  
   712  func (s *storageMockSuite) TestRemoveDestroyV3(c *gc.C) {
   713  	apiCaller := basetesting.BestVersionCaller{
   714  		APICallerFunc: basetesting.APICallerFunc(
   715  			func(objType string,
   716  				version int,
   717  				id, request string,
   718  				a, result interface{},
   719  			) error {
   720  				c.Check(objType, gc.Equals, "Storage")
   721  				c.Check(id, gc.Equals, "")
   722  				c.Check(request, gc.Equals, "Destroy")
   723  				c.Check(a, jc.DeepEquals, params.Entities{[]params.Entity{
   724  					{Tag: "storage-foo-0"},
   725  				}})
   726  				results := result.(*params.ErrorResults)
   727  				results.Results = []params.ErrorResult{{}}
   728  				return nil
   729  			},
   730  		),
   731  		BestVersion: 3,
   732  	}
   733  	client := storage.NewClient(apiCaller)
   734  	results, err := client.Remove([]string{"foo/0"}, true, true)
   735  	c.Check(err, jc.ErrorIsNil)
   736  	c.Assert(results, gc.HasLen, 1)
   737  	c.Assert(results[0].Error, gc.IsNil)
   738  }
   739  
   740  func (s *storageMockSuite) TestRemoveDestroyV3NoDestroyStorage(c *gc.C) {
   741  	apiCaller := basetesting.BestVersionCaller{BestVersion: 3}
   742  	client := storage.NewClient(apiCaller)
   743  	_, err := client.Remove([]string{"foo/0"}, true, false)
   744  	c.Check(err, gc.ErrorMatches, "this juju controller does not support non-destructive removal of storage")
   745  }
   746  
   747  func (s *storageMockSuite) TestRemoveInvalidStorageId(c *gc.C) {
   748  	client := storage.NewClient(basetesting.APICallerFunc(
   749  		func(_ string, _ int, _, _ string, _, _ interface{}) error {
   750  			return nil
   751  		},
   752  	))
   753  	_, err := client.Remove([]string{"foo/bar"}, false, false)
   754  	c.Check(err, gc.ErrorMatches, `storage ID "foo/bar" not valid`)
   755  }
   756  
   757  func (s *storageMockSuite) TestDetach(c *gc.C) {
   758  	apiCaller := basetesting.APICallerFunc(
   759  		func(objType string,
   760  			version int,
   761  			id, request string,
   762  			a, result interface{},
   763  		) error {
   764  			c.Check(objType, gc.Equals, "Storage")
   765  			c.Check(id, gc.Equals, "")
   766  			c.Check(request, gc.Equals, "Detach")
   767  			c.Check(a, jc.DeepEquals, params.StorageAttachmentIds{[]params.StorageAttachmentId{
   768  				{StorageTag: "storage-foo-0"},
   769  				{StorageTag: "storage-bar-1"},
   770  			}})
   771  			c.Assert(result, gc.FitsTypeOf, &params.ErrorResults{})
   772  			results := result.(*params.ErrorResults)
   773  			results.Results = []params.ErrorResult{
   774  				{},
   775  				{Error: &params.Error{Message: "baz"}},
   776  			}
   777  			return nil
   778  		},
   779  	)
   780  	client := storage.NewClient(apiCaller)
   781  	results, err := client.Detach([]string{"foo/0", "bar/1"})
   782  	c.Check(err, jc.ErrorIsNil)
   783  	c.Assert(results, gc.HasLen, 2)
   784  	c.Assert(results[0].Error, gc.IsNil)
   785  	c.Assert(results[1].Error, jc.DeepEquals, &params.Error{Message: "baz"})
   786  }
   787  
   788  func (s *storageMockSuite) TestDetachArityMismatch(c *gc.C) {
   789  	apiCaller := basetesting.APICallerFunc(
   790  		func(objType string, version int, id, request string, a, result interface{}) error {
   791  			results := result.(*params.ErrorResults)
   792  			results.Results = []params.ErrorResult{{}, {}, {}}
   793  			return nil
   794  		},
   795  	)
   796  	client := storage.NewClient(apiCaller)
   797  	_, err := client.Detach([]string{"foo/0", "bar/1"})
   798  	c.Check(err, gc.ErrorMatches, `expected 2 result\(s\), got 3`)
   799  }
   800  
   801  func (s *storageMockSuite) TestAttach(c *gc.C) {
   802  	apiCaller := basetesting.APICallerFunc(
   803  		func(objType string,
   804  			version int,
   805  			id, request string,
   806  			a, result interface{},
   807  		) error {
   808  			c.Check(objType, gc.Equals, "Storage")
   809  			c.Check(id, gc.Equals, "")
   810  			c.Check(request, gc.Equals, "Attach")
   811  			c.Check(a, jc.DeepEquals, params.StorageAttachmentIds{[]params.StorageAttachmentId{
   812  				{
   813  					StorageTag: "storage-bar-1",
   814  					UnitTag:    "unit-foo-0",
   815  				},
   816  				{
   817  					StorageTag: "storage-baz-2",
   818  					UnitTag:    "unit-foo-0",
   819  				},
   820  			}})
   821  			c.Assert(result, gc.FitsTypeOf, &params.ErrorResults{})
   822  			results := result.(*params.ErrorResults)
   823  			results.Results = []params.ErrorResult{
   824  				{},
   825  				{Error: &params.Error{Message: "qux"}},
   826  			}
   827  			return nil
   828  		},
   829  	)
   830  	client := storage.NewClient(apiCaller)
   831  	results, err := client.Attach("foo/0", []string{"bar/1", "baz/2"})
   832  	c.Check(err, jc.ErrorIsNil)
   833  	c.Assert(results, gc.HasLen, 2)
   834  	c.Assert(results[0].Error, gc.IsNil)
   835  	c.Assert(results[1].Error, jc.DeepEquals, &params.Error{Message: "qux"})
   836  }
   837  
   838  func (s *storageMockSuite) TestAttachArityMismatch(c *gc.C) {
   839  	apiCaller := basetesting.APICallerFunc(
   840  		func(objType string, version int, id, request string, a, result interface{}) error {
   841  			results := result.(*params.ErrorResults)
   842  			results.Results = []params.ErrorResult{{}, {}, {}}
   843  			return nil
   844  		},
   845  	)
   846  	client := storage.NewClient(apiCaller)
   847  	_, err := client.Attach("foo/0", []string{"bar/1", "baz/2"})
   848  	c.Check(err, gc.ErrorMatches, `expected 2 result\(s\), got 3`)
   849  }
   850  
   851  func (s *storageMockSuite) TestImport(c *gc.C) {
   852  	apiCaller := basetesting.APICallerFunc(
   853  		func(objType string,
   854  			version int,
   855  			id, request string,
   856  			a, result interface{},
   857  		) error {
   858  			c.Check(objType, gc.Equals, "Storage")
   859  			c.Check(id, gc.Equals, "")
   860  			c.Check(request, gc.Equals, "Import")
   861  			c.Check(a, jc.DeepEquals, params.BulkImportStorageParams{[]params.ImportStorageParams{{
   862  				Kind:        params.StorageKindBlock,
   863  				Pool:        "foo",
   864  				ProviderId:  "bar",
   865  				StorageName: "baz",
   866  			}}})
   867  			c.Assert(result, gc.FitsTypeOf, &params.ImportStorageResults{})
   868  			results := result.(*params.ImportStorageResults)
   869  			results.Results = []params.ImportStorageResult{{
   870  				Result: &params.ImportStorageDetails{
   871  					StorageTag: "storage-qux-0",
   872  				},
   873  			}}
   874  			return nil
   875  		},
   876  	)
   877  	client := storage.NewClient(apiCaller)
   878  	storageTag, err := client.Import(jujustorage.StorageKindBlock, "foo", "bar", "baz")
   879  	c.Assert(err, jc.ErrorIsNil)
   880  	c.Assert(storageTag, gc.Equals, names.NewStorageTag("qux/0"))
   881  }
   882  
   883  func (s *storageMockSuite) TestImportError(c *gc.C) {
   884  	apiCaller := basetesting.APICallerFunc(
   885  		func(objType string, version int, id, request string, a, result interface{}) error {
   886  			results := result.(*params.ImportStorageResults)
   887  			results.Results = []params.ImportStorageResult{{
   888  				Error: &params.Error{Message: "qux"},
   889  			}}
   890  			return nil
   891  		},
   892  	)
   893  	client := storage.NewClient(apiCaller)
   894  	_, err := client.Import(jujustorage.StorageKindBlock, "foo", "bar", "baz")
   895  	c.Check(err, gc.ErrorMatches, "qux")
   896  }
   897  
   898  func (s *storageMockSuite) TestImportArityMismatch(c *gc.C) {
   899  	apiCaller := basetesting.APICallerFunc(
   900  		func(objType string, version int, id, request string, a, result interface{}) error {
   901  			results := result.(*params.ImportStorageResults)
   902  			results.Results = []params.ImportStorageResult{{}, {}}
   903  			return nil
   904  		},
   905  	)
   906  	client := storage.NewClient(apiCaller)
   907  	_, err := client.Import(jujustorage.StorageKindBlock, "foo", "bar", "baz")
   908  	c.Check(err, gc.ErrorMatches, `expected 1 result, got 2`)
   909  }
   910  
   911  func (s *storageMockSuite) TestRemovePool(c *gc.C) {
   912  	var called bool
   913  	poolName := "poolName"
   914  
   915  	apiCaller := basetesting.APICallerFunc(
   916  		func(objType string,
   917  			version int,
   918  			id, request string,
   919  			a, result interface{},
   920  		) error {
   921  			called = true
   922  			c.Check(objType, gc.Equals, "Storage")
   923  			c.Check(id, gc.Equals, "")
   924  			c.Check(request, gc.Equals, "RemovePool")
   925  
   926  			args, ok := a.(params.StoragePoolDeleteArgs)
   927  			c.Assert(ok, jc.IsTrue)
   928  			c.Assert(args.Pools, gc.HasLen, 1)
   929  			c.Assert(args.Pools[0].Name, gc.Equals, poolName)
   930  
   931  			results := result.(*params.ErrorResults)
   932  			results.Results = make([]params.ErrorResult, len(args.Pools))
   933  
   934  			return nil
   935  		})
   936  	storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller})
   937  	err := storageClient.RemovePool(poolName)
   938  	c.Assert(err, jc.ErrorIsNil)
   939  	c.Assert(called, jc.IsTrue)
   940  }
   941  
   942  func (s *storageMockSuite) TestRemovePoolFacadeCallError(c *gc.C) {
   943  	msg := "facade failure"
   944  	apiCaller := basetesting.APICallerFunc(
   945  		func(objType string,
   946  			version int,
   947  			id, request string,
   948  			a, result interface{},
   949  		) error {
   950  			c.Check(objType, gc.Equals, "Storage")
   951  			c.Check(id, gc.Equals, "")
   952  			c.Check(request, gc.Equals, "RemovePool")
   953  
   954  			args, ok := a.(params.StoragePoolDeleteArgs)
   955  			c.Assert(ok, jc.IsTrue)
   956  			c.Assert(args.Pools, gc.HasLen, 1)
   957  			c.Assert(args.Pools[0].Name, gc.Equals, "")
   958  
   959  			results := result.(*params.ErrorResults)
   960  			results.Results = make([]params.ErrorResult, len(args.Pools))
   961  			return errors.New(msg)
   962  		})
   963  	storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller})
   964  	err := storageClient.RemovePool("")
   965  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
   966  }
   967  
   968  func (s *storageMockSuite) TestUpdatePool(c *gc.C) {
   969  	var called bool
   970  	poolName := "poolName"
   971  	providerType := "loop"
   972  	poolConfig := map[string]interface{}{
   973  		"test": "one",
   974  		"pass": true,
   975  	}
   976  
   977  	apiCaller := basetesting.APICallerFunc(
   978  		func(objType string,
   979  			version int,
   980  			id, request string,
   981  			a, result interface{},
   982  		) error {
   983  			called = true
   984  			c.Check(objType, gc.Equals, "Storage")
   985  			c.Check(id, gc.Equals, "")
   986  			c.Check(request, gc.Equals, "UpdatePool")
   987  
   988  			args, ok := a.(params.StoragePoolArgs)
   989  			c.Assert(ok, jc.IsTrue)
   990  			c.Assert(args.Pools, gc.HasLen, 1)
   991  			c.Assert(args.Pools[0].Name, gc.Equals, poolName)
   992  			c.Assert(args.Pools[0].Provider, gc.Equals, providerType)
   993  			c.Assert(args.Pools[0].Attrs, gc.DeepEquals, poolConfig)
   994  
   995  			results := result.(*params.ErrorResults)
   996  			results.Results = make([]params.ErrorResult, len(args.Pools))
   997  
   998  			return nil
   999  		})
  1000  	storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller})
  1001  	err := storageClient.UpdatePool(poolName, providerType, poolConfig)
  1002  	c.Assert(err, jc.ErrorIsNil)
  1003  	c.Assert(called, jc.IsTrue)
  1004  }
  1005  
  1006  func (s *storageMockSuite) TestUpdatePoolFacadeCallError(c *gc.C) {
  1007  	msg := "facade failure"
  1008  	apiCaller := basetesting.APICallerFunc(
  1009  		func(objType string,
  1010  			version int,
  1011  			id, request string,
  1012  			a, result interface{},
  1013  		) error {
  1014  			c.Check(objType, gc.Equals, "Storage")
  1015  			c.Check(id, gc.Equals, "")
  1016  			c.Check(request, gc.Equals, "UpdatePool")
  1017  
  1018  			return errors.New(msg)
  1019  		})
  1020  	storageClient := storage.NewClient(basetesting.BestVersionCaller{BestVersion: 5, APICallerFunc: apiCaller})
  1021  	err := storageClient.UpdatePool("", "", nil)
  1022  	c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
  1023  }