github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/common/destroy_test.go (about)

     1  // Copyright 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"strings"
    10  
    11  	gitjujutesting "github.com/juju/testing"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/core/instance"
    16  	"github.com/juju/juju/environs"
    17  	"github.com/juju/juju/environs/context"
    18  	"github.com/juju/juju/environs/instances"
    19  	"github.com/juju/juju/provider/common"
    20  	"github.com/juju/juju/storage"
    21  	"github.com/juju/juju/storage/provider/dummy"
    22  	"github.com/juju/juju/testing"
    23  	jujuversion "github.com/juju/juju/version"
    24  )
    25  
    26  type DestroySuite struct {
    27  	testing.BaseSuite
    28  
    29  	callCtx context.ProviderCallContext
    30  }
    31  
    32  var _ = gc.Suite(&DestroySuite{})
    33  
    34  func (s *DestroySuite) SetUpTest(c *gc.C) {
    35  	s.BaseSuite.SetUpTest(c)
    36  	s.callCtx = context.NewCloudCallContext()
    37  }
    38  
    39  func (s *DestroySuite) TestCannotGetInstances(c *gc.C) {
    40  	env := &mockEnviron{
    41  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
    42  			return nil, fmt.Errorf("nope")
    43  		},
    44  		config: configGetter(c),
    45  	}
    46  	err := common.Destroy(env, s.callCtx)
    47  	c.Assert(err, gc.ErrorMatches, "destroying instances: nope")
    48  }
    49  
    50  func (s *DestroySuite) TestCannotStopInstances(c *gc.C) {
    51  	env := &mockEnviron{
    52  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
    53  			return []instances.Instance{
    54  				&mockInstance{id: "one"},
    55  				&mockInstance{id: "another"},
    56  			}, nil
    57  		},
    58  		stopInstances: func(ctx context.ProviderCallContext, ids []instance.Id) error {
    59  			c.Assert(ids, gc.HasLen, 2)
    60  			c.Assert(ids[0], gc.Equals, instance.Id("one"))
    61  			c.Assert(ids[1], gc.Equals, instance.Id("another"))
    62  			return fmt.Errorf("nah")
    63  		},
    64  		config: configGetter(c),
    65  	}
    66  	err := common.Destroy(env, s.callCtx)
    67  	c.Assert(err, gc.ErrorMatches, "destroying instances: nah")
    68  }
    69  
    70  func (s *DestroySuite) TestSuccessWhenStorageErrors(c *gc.C) {
    71  	// common.Destroy doesn't touch provider/object storage anymore,
    72  	// so failing storage should not affect success.
    73  	env := &mockEnviron{
    74  		storage: &mockStorage{removeAllErr: fmt.Errorf("noes!")},
    75  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
    76  			return []instances.Instance{
    77  				&mockInstance{id: "one"},
    78  				&mockInstance{id: "another"},
    79  			}, nil
    80  		},
    81  		stopInstances: func(ctx context.ProviderCallContext, ids []instance.Id) error {
    82  			c.Assert(ids, gc.HasLen, 2)
    83  			c.Assert(ids[0], gc.Equals, instance.Id("one"))
    84  			c.Assert(ids[1], gc.Equals, instance.Id("another"))
    85  			return nil
    86  		},
    87  		config: configGetter(c),
    88  	}
    89  	err := common.Destroy(env, s.callCtx)
    90  	c.Assert(err, jc.ErrorIsNil)
    91  }
    92  
    93  func (s *DestroySuite) TestSuccess(c *gc.C) {
    94  	s.PatchValue(&jujuversion.Current, testing.FakeVersionNumber)
    95  	stor := newStorage(s, c)
    96  	err := stor.Put("somewhere", strings.NewReader("stuff"), 5)
    97  	c.Assert(err, jc.ErrorIsNil)
    98  
    99  	env := &mockEnviron{
   100  		storage: stor,
   101  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   102  			return []instances.Instance{
   103  				&mockInstance{id: "one"},
   104  			}, nil
   105  		},
   106  		stopInstances: func(ctx context.ProviderCallContext, ids []instance.Id) error {
   107  			c.Assert(ids, gc.HasLen, 1)
   108  			c.Assert(ids[0], gc.Equals, instance.Id("one"))
   109  			return nil
   110  		},
   111  		config: configGetter(c),
   112  	}
   113  	err = common.Destroy(env, s.callCtx)
   114  	c.Assert(err, jc.ErrorIsNil)
   115  
   116  	// common.Destroy doesn't touch provider/object storage anymore.
   117  	r, err := stor.Get("somewhere")
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	r.Close()
   120  }
   121  
   122  func (s *DestroySuite) TestSuccessWhenNoInstances(c *gc.C) {
   123  	s.PatchValue(&jujuversion.Current, testing.FakeVersionNumber)
   124  	stor := newStorage(s, c)
   125  	err := stor.Put("elsewhere", strings.NewReader("stuff"), 5)
   126  	c.Assert(err, jc.ErrorIsNil)
   127  
   128  	env := &mockEnviron{
   129  		storage: stor,
   130  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   131  			return nil, environs.ErrNoInstances
   132  		},
   133  		config: configGetter(c),
   134  	}
   135  	err = common.Destroy(env, s.callCtx)
   136  	c.Assert(err, jc.ErrorIsNil)
   137  }
   138  
   139  func (s *DestroySuite) TestDestroyEnvScopedVolumes(c *gc.C) {
   140  	volumeSource := &dummy.VolumeSource{
   141  		ListVolumesFunc: func(ctx context.ProviderCallContext) ([]string, error) {
   142  			return []string{"vol-0", "vol-1", "vol-2"}, nil
   143  		},
   144  		DestroyVolumesFunc: func(ctx context.ProviderCallContext, ids []string) ([]error, error) {
   145  			return make([]error, len(ids)), nil
   146  		},
   147  	}
   148  	storageProvider := &dummy.StorageProvider{
   149  		IsDynamic:    true,
   150  		StorageScope: storage.ScopeEnviron,
   151  		VolumeSourceFunc: func(*storage.Config) (storage.VolumeSource, error) {
   152  			return volumeSource, nil
   153  		},
   154  	}
   155  
   156  	env := &mockEnviron{
   157  		config: configGetter(c),
   158  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   159  			return nil, environs.ErrNoInstances
   160  		},
   161  		storageProviders: storage.StaticProviderRegistry{
   162  			map[storage.ProviderType]storage.Provider{
   163  				"environ": storageProvider,
   164  			},
   165  		},
   166  	}
   167  	err := common.Destroy(env, s.callCtx)
   168  	c.Assert(err, jc.ErrorIsNil)
   169  
   170  	// common.Destroy will ignore machine-scoped storage providers.
   171  	storageProvider.CheckCallNames(c, "Dynamic", "Scope", "Supports", "VolumeSource")
   172  	volumeSource.CheckCalls(c, []gitjujutesting.StubCall{
   173  		{"ListVolumes", []interface{}{s.callCtx}},
   174  		{"DestroyVolumes", []interface{}{s.callCtx, []string{"vol-0", "vol-1", "vol-2"}}},
   175  	})
   176  }
   177  
   178  func (s *DestroySuite) TestDestroyVolumeErrors(c *gc.C) {
   179  	volumeSource := &dummy.VolumeSource{
   180  		ListVolumesFunc: func(ctx context.ProviderCallContext) ([]string, error) {
   181  			return []string{"vol-0", "vol-1", "vol-2"}, nil
   182  		},
   183  		DestroyVolumesFunc: func(ctx context.ProviderCallContext, ids []string) ([]error, error) {
   184  			return []error{
   185  				nil,
   186  				errors.New("cannot destroy vol-1"),
   187  				errors.New("cannot destroy vol-2"),
   188  			}, nil
   189  		},
   190  	}
   191  
   192  	storageProvider := &dummy.StorageProvider{
   193  		IsDynamic:    true,
   194  		StorageScope: storage.ScopeEnviron,
   195  		VolumeSourceFunc: func(*storage.Config) (storage.VolumeSource, error) {
   196  			return volumeSource, nil
   197  		},
   198  	}
   199  
   200  	env := &mockEnviron{
   201  		config: configGetter(c),
   202  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   203  			return nil, environs.ErrNoInstances
   204  		},
   205  		storageProviders: storage.StaticProviderRegistry{
   206  			map[storage.ProviderType]storage.Provider{
   207  				"environ": storageProvider,
   208  			},
   209  		},
   210  	}
   211  	err := common.Destroy(env, s.callCtx)
   212  	c.Assert(err, gc.ErrorMatches, "destroying storage: destroying volumes: cannot destroy vol-1, cannot destroy vol-2")
   213  }
   214  
   215  func (s *DestroySuite) TestIgnoreStaticVolumes(c *gc.C) {
   216  	staticProvider := &dummy.StorageProvider{
   217  		IsDynamic:    false,
   218  		StorageScope: storage.ScopeEnviron,
   219  	}
   220  
   221  	env := &mockEnviron{
   222  		config: configGetter(c),
   223  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   224  			return nil, environs.ErrNoInstances
   225  		},
   226  		storageProviders: storage.StaticProviderRegistry{
   227  			map[storage.ProviderType]storage.Provider{
   228  				"static": staticProvider,
   229  			},
   230  		},
   231  	}
   232  	err := common.Destroy(env, s.callCtx)
   233  	c.Assert(err, jc.ErrorIsNil)
   234  
   235  	// common.Destroy will ignore static storage providers.
   236  	staticProvider.CheckCallNames(c, "Dynamic")
   237  }
   238  
   239  func (s *DestroySuite) TestIgnoreMachineScopedVolumes(c *gc.C) {
   240  	staticProvider := &dummy.StorageProvider{
   241  		IsDynamic:    true,
   242  		StorageScope: storage.ScopeMachine,
   243  	}
   244  
   245  	env := &mockEnviron{
   246  		config: configGetter(c),
   247  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   248  			return nil, environs.ErrNoInstances
   249  		},
   250  		storageProviders: storage.StaticProviderRegistry{
   251  			map[storage.ProviderType]storage.Provider{
   252  				"static": staticProvider,
   253  			},
   254  		},
   255  	}
   256  	err := common.Destroy(env, s.callCtx)
   257  	c.Assert(err, jc.ErrorIsNil)
   258  
   259  	// common.Destroy will ignore machine-scoped storage providers.
   260  	staticProvider.CheckCallNames(c, "Dynamic", "Scope")
   261  }
   262  
   263  func (s *DestroySuite) TestIgnoreNoVolumeSupport(c *gc.C) {
   264  	staticProvider := &dummy.StorageProvider{
   265  		IsDynamic:    true,
   266  		StorageScope: storage.ScopeEnviron,
   267  		SupportsFunc: func(storage.StorageKind) bool {
   268  			return false
   269  		},
   270  	}
   271  
   272  	env := &mockEnviron{
   273  		config: configGetter(c),
   274  		allInstances: func(context.ProviderCallContext) ([]instances.Instance, error) {
   275  			return nil, environs.ErrNoInstances
   276  		},
   277  		storageProviders: storage.StaticProviderRegistry{
   278  			map[storage.ProviderType]storage.Provider{
   279  				"static": staticProvider,
   280  			},
   281  		},
   282  	}
   283  	err := common.Destroy(env, s.callCtx)
   284  	c.Assert(err, jc.ErrorIsNil)
   285  
   286  	// common.Destroy will ignore storage providers that don't support
   287  	// volumes (until we have persistent filesystems, that is).
   288  	staticProvider.CheckCallNames(c, "Dynamic", "Scope", "Supports")
   289  }