github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/api/machineundertaker/undertaker_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package machineundertaker_test 5 6 import ( 7 "github.com/juju/errors" 8 jc "github.com/juju/testing/checkers" 9 gc "gopkg.in/check.v1" 10 "gopkg.in/juju/names.v2" 11 12 "github.com/juju/juju/api/base" 13 "github.com/juju/juju/api/base/testing" 14 "github.com/juju/juju/api/machineundertaker" 15 "github.com/juju/juju/apiserver/common" 16 "github.com/juju/juju/apiserver/params" 17 "github.com/juju/juju/network" 18 coretesting "github.com/juju/juju/testing" 19 "github.com/juju/juju/watcher" 20 ) 21 22 type undertakerSuite struct { 23 coretesting.BaseSuite 24 } 25 26 var _ = gc.Suite(&undertakerSuite{}) 27 28 func (s *undertakerSuite) TestRequiresModelConnection(c *gc.C) { 29 api, err := machineundertaker.NewAPI(&fakeAPICaller{hasModelTag: false}, nil) 30 c.Assert(err, gc.ErrorMatches, "machine undertaker client requires a model API connection") 31 c.Assert(api, gc.IsNil) 32 api, err = machineundertaker.NewAPI(&fakeAPICaller{hasModelTag: true}, nil) 33 c.Assert(err, jc.ErrorIsNil) 34 c.Assert(api, gc.NotNil) 35 } 36 37 func (s *undertakerSuite) TestAllMachineRemovals(c *gc.C) { 38 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 39 c.Check(facade, gc.Equals, "MachineUndertaker") 40 c.Check(request, gc.Equals, "AllMachineRemovals") 41 c.Check(version, gc.Equals, 0) 42 c.Check(id, gc.Equals, "") 43 c.Check(arg, gc.DeepEquals, wrapEntities(coretesting.ModelTag.String())) 44 c.Assert(result, gc.FitsTypeOf, ¶ms.EntitiesResults{}) 45 *result.(*params.EntitiesResults) = *wrapEntitiesResults("machine-23", "machine-42") 46 return nil 47 } 48 api := makeAPI(c, caller) 49 results, err := api.AllMachineRemovals() 50 c.Assert(err, jc.ErrorIsNil) 51 c.Assert(results, gc.DeepEquals, []names.MachineTag{ 52 names.NewMachineTag("23"), 53 names.NewMachineTag("42"), 54 }) 55 } 56 57 func (s *undertakerSuite) TestAllMachineRemovals_Error(c *gc.C) { 58 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 59 return errors.New("restless year") 60 } 61 api := makeAPI(c, caller) 62 results, err := api.AllMachineRemovals() 63 c.Assert(err, gc.ErrorMatches, "restless year") 64 c.Assert(results, gc.IsNil) 65 } 66 67 func (s *undertakerSuite) TestAllMachineRemovals_BadTag(c *gc.C) { 68 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 69 c.Assert(result, gc.FitsTypeOf, ¶ms.EntitiesResults{}) 70 *result.(*params.EntitiesResults) = *wrapEntitiesResults("machine-23", "application-burp") 71 return nil 72 } 73 api := makeAPI(c, caller) 74 results, err := api.AllMachineRemovals() 75 c.Assert(err, gc.ErrorMatches, `"application-burp" is not a valid machine tag`) 76 c.Assert(results, gc.IsNil) 77 } 78 79 func (s *undertakerSuite) TestAllMachineRemovals_ErrorResult(c *gc.C) { 80 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 81 c.Assert(result, gc.FitsTypeOf, ¶ms.EntitiesResults{}) 82 *result.(*params.EntitiesResults) = params.EntitiesResults{ 83 Results: []params.EntitiesResult{{ 84 Error: common.ServerError(errors.New("everythingisterrible")), 85 }}, 86 } 87 return nil 88 } 89 api := makeAPI(c, caller) 90 results, err := api.AllMachineRemovals() 91 c.Assert(err, gc.ErrorMatches, "everythingisterrible") 92 c.Assert(results, gc.IsNil) 93 } 94 95 func (s *undertakerSuite) TestAllMachineRemovals_TooManyResults(c *gc.C) { 96 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 97 c.Assert(result, gc.FitsTypeOf, ¶ms.EntitiesResults{}) 98 *result.(*params.EntitiesResults) = params.EntitiesResults{ 99 Results: []params.EntitiesResult{{ 100 Entities: []params.Entity{{Tag: "machine-1"}}, 101 }, { 102 Entities: []params.Entity{{Tag: "machine-2"}}, 103 }}, 104 } 105 return nil 106 } 107 api := makeAPI(c, caller) 108 results, err := api.AllMachineRemovals() 109 c.Assert(err, gc.ErrorMatches, "expected one result, got 2") 110 c.Assert(results, gc.IsNil) 111 } 112 113 func (s *undertakerSuite) TestAllMachineRemovals_TooFewResults(c *gc.C) { 114 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 115 c.Assert(result, gc.FitsTypeOf, ¶ms.EntitiesResults{}) 116 *result.(*params.EntitiesResults) = params.EntitiesResults{} 117 return nil 118 } 119 api := makeAPI(c, caller) 120 results, err := api.AllMachineRemovals() 121 c.Assert(err, gc.ErrorMatches, "expected one result, got 0") 122 c.Assert(results, gc.IsNil) 123 } 124 125 func (*undertakerSuite) TestGetInfo(c *gc.C) { 126 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 127 c.Check(facade, gc.Equals, "MachineUndertaker") 128 c.Check(request, gc.Equals, "GetMachineProviderInterfaceInfo") 129 c.Check(version, gc.Equals, 0) 130 c.Check(id, gc.Equals, "") 131 c.Check(arg, gc.DeepEquals, wrapEntities("machine-100")) 132 c.Assert(result, gc.FitsTypeOf, ¶ms.ProviderInterfaceInfoResults{}) 133 *result.(*params.ProviderInterfaceInfoResults) = params.ProviderInterfaceInfoResults{ 134 Results: []params.ProviderInterfaceInfoResult{{ 135 MachineTag: "machine-100", 136 Interfaces: []params.ProviderInterfaceInfo{{ 137 InterfaceName: "hamster huey", 138 MACAddress: "calvin", 139 ProviderId: "1234", 140 }, { 141 InterfaceName: "happy hamster hop", 142 MACAddress: "hobbes", 143 ProviderId: "1235", 144 }}, 145 }}, 146 } 147 return nil 148 } 149 api := makeAPI(c, caller) 150 results, err := api.GetProviderInterfaceInfo(names.NewMachineTag("100")) 151 c.Assert(err, jc.ErrorIsNil) 152 c.Assert(results, gc.DeepEquals, []network.ProviderInterfaceInfo{{ 153 InterfaceName: "hamster huey", 154 MACAddress: "calvin", 155 ProviderId: "1234", 156 }, { 157 InterfaceName: "happy hamster hop", 158 MACAddress: "hobbes", 159 ProviderId: "1235", 160 }}) 161 } 162 163 func (*undertakerSuite) TestGetInfo_GenericError(c *gc.C) { 164 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 165 return errors.New("gooey kablooey") 166 } 167 api := makeAPI(c, caller) 168 results, err := api.GetProviderInterfaceInfo(names.NewMachineTag("100")) 169 c.Assert(err, gc.ErrorMatches, "gooey kablooey") 170 c.Assert(results, gc.IsNil) 171 } 172 173 func (*undertakerSuite) TestGetInfo_TooMany(c *gc.C) { 174 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 175 c.Assert(result, gc.FitsTypeOf, ¶ms.ProviderInterfaceInfoResults{}) 176 *result.(*params.ProviderInterfaceInfoResults) = params.ProviderInterfaceInfoResults{ 177 Results: []params.ProviderInterfaceInfoResult{{ 178 MachineTag: "machine-100", 179 Interfaces: []params.ProviderInterfaceInfo{{ 180 InterfaceName: "hamster huey", 181 MACAddress: "calvin", 182 ProviderId: "1234", 183 }}, 184 }, { 185 MachineTag: "machine-101", 186 Interfaces: []params.ProviderInterfaceInfo{{ 187 InterfaceName: "hamster huey", 188 MACAddress: "calvin", 189 ProviderId: "1234", 190 }}, 191 }}, 192 } 193 return nil 194 } 195 api := makeAPI(c, caller) 196 results, err := api.GetProviderInterfaceInfo(names.NewMachineTag("100")) 197 c.Assert(err, gc.ErrorMatches, "expected one result, got 2") 198 c.Assert(results, gc.IsNil) 199 } 200 201 func (*undertakerSuite) TestGetInfo_BadMachine(c *gc.C) { 202 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 203 c.Assert(result, gc.FitsTypeOf, ¶ms.ProviderInterfaceInfoResults{}) 204 *result.(*params.ProviderInterfaceInfoResults) = params.ProviderInterfaceInfoResults{ 205 Results: []params.ProviderInterfaceInfoResult{{ 206 MachineTag: "machine-101", 207 Interfaces: []params.ProviderInterfaceInfo{{ 208 InterfaceName: "hamster huey", 209 MACAddress: "calvin", 210 ProviderId: "1234", 211 }}, 212 }}, 213 } 214 return nil 215 } 216 api := makeAPI(c, caller) 217 results, err := api.GetProviderInterfaceInfo(names.NewMachineTag("100")) 218 c.Assert(err, gc.ErrorMatches, "expected interface info for machine-100 but got machine-101") 219 c.Assert(results, gc.IsNil) 220 } 221 222 func (*undertakerSuite) TestCompleteRemoval(c *gc.C) { 223 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 224 c.Check(facade, gc.Equals, "MachineUndertaker") 225 c.Check(request, gc.Equals, "CompleteMachineRemovals") 226 c.Check(version, gc.Equals, 0) 227 c.Check(id, gc.Equals, "") 228 c.Check(arg, gc.DeepEquals, wrapEntities("machine-100")) 229 c.Check(result, gc.DeepEquals, nil) 230 return errors.New("gooey kablooey") 231 } 232 api := makeAPI(c, caller) 233 err := api.CompleteRemoval(names.NewMachineTag("100")) 234 c.Assert(err, gc.ErrorMatches, "gooey kablooey") 235 } 236 237 func (*undertakerSuite) TestWatchMachineRemovals_CallFailed(c *gc.C) { 238 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 239 c.Check(facade, gc.Equals, "MachineUndertaker") 240 c.Check(request, gc.Equals, "WatchMachineRemovals") 241 c.Check(version, gc.Equals, 0) 242 c.Check(id, gc.Equals, "") 243 c.Check(arg, gc.DeepEquals, wrapEntities(coretesting.ModelTag.String())) 244 return errors.New("oopsy") 245 } 246 api := makeAPI(c, caller) 247 w, err := api.WatchMachineRemovals() 248 c.Check(w, gc.IsNil) 249 c.Assert(err, gc.ErrorMatches, "oopsy") 250 } 251 252 func (*undertakerSuite) TestWatchMachineRemovals_ErrorInWatcher(c *gc.C) { 253 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 254 c.Assert(result, gc.FitsTypeOf, ¶ms.NotifyWatchResults{}) 255 *result.(*params.NotifyWatchResults) = params.NotifyWatchResults{ 256 Results: []params.NotifyWatchResult{{ 257 Error: ¶ms.Error{Message: "blammo"}, 258 }}, 259 } 260 return nil 261 } 262 api := makeAPI(c, caller) 263 w, err := api.WatchMachineRemovals() 264 c.Check(w, gc.IsNil) 265 c.Assert(err, gc.ErrorMatches, "blammo") 266 } 267 268 func (*undertakerSuite) TestWatchMachineRemovals_TooMany(c *gc.C) { 269 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 270 c.Assert(result, gc.FitsTypeOf, ¶ms.NotifyWatchResults{}) 271 *result.(*params.NotifyWatchResults) = params.NotifyWatchResults{ 272 Results: []params.NotifyWatchResult{{ 273 NotifyWatcherId: "2", 274 }, { 275 NotifyWatcherId: "3", 276 }}, 277 } 278 return nil 279 } 280 api := makeAPI(c, caller) 281 w, err := api.WatchMachineRemovals() 282 c.Check(w, gc.IsNil) 283 c.Assert(err, gc.ErrorMatches, "expected one result, got 2") 284 } 285 286 func (*undertakerSuite) TestWatchMachineRemovals_Success(c *gc.C) { 287 caller := func(facade string, version int, id, request string, arg, result interface{}) error { 288 c.Assert(result, gc.FitsTypeOf, ¶ms.NotifyWatchResults{}) 289 *result.(*params.NotifyWatchResults) = params.NotifyWatchResults{ 290 Results: []params.NotifyWatchResult{{ 291 NotifyWatcherId: "2", 292 }}, 293 } 294 return nil 295 } 296 expectWatcher := &struct{ watcher.NotifyWatcher }{} 297 newWatcher := func(wcaller base.APICaller, result params.NotifyWatchResult) watcher.NotifyWatcher { 298 c.Check(wcaller, gc.NotNil) // not comparable 299 c.Check(result, gc.DeepEquals, params.NotifyWatchResult{ 300 NotifyWatcherId: "2", 301 }) 302 return expectWatcher 303 } 304 305 api, err := machineundertaker.NewAPI(testing.APICallerFunc(caller), newWatcher) 306 c.Check(err, jc.ErrorIsNil) 307 w, err := api.WatchMachineRemovals() 308 c.Check(err, jc.ErrorIsNil) 309 c.Check(w, gc.Equals, expectWatcher) 310 } 311 312 func makeAPI(c *gc.C, caller testing.APICallerFunc) *machineundertaker.API { 313 api, err := machineundertaker.NewAPI(caller, nil) 314 c.Assert(err, jc.ErrorIsNil) 315 return api 316 } 317 318 func wrapEntities(tags ...string) *params.Entities { 319 return ¶ms.Entities{Entities: makeEntitySlice(tags...)} 320 } 321 322 func makeEntitySlice(tags ...string) []params.Entity { 323 results := make([]params.Entity, len(tags)) 324 for i := range tags { 325 results[i].Tag = tags[i] 326 } 327 return results 328 } 329 330 func wrapEntitiesResults(tags ...string) *params.EntitiesResults { 331 return ¶ms.EntitiesResults{ 332 Results: []params.EntitiesResult{{ 333 Entities: makeEntitySlice(tags...), 334 }}, 335 } 336 } 337 338 type fakeAPICaller struct { 339 base.APICaller 340 hasModelTag bool 341 } 342 343 func (c *fakeAPICaller) ModelTag() (names.ModelTag, bool) { 344 return names.ModelTag{}, c.hasModelTag 345 } 346 347 func (c *fakeAPICaller) BestFacadeVersion(string) int { 348 return 0 349 }