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 }