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, &params.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, &params.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, &params.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, &params.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, &params.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, &params.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, &params.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, &params.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, &params.NotifyWatchResults{})
   255  		*result.(*params.NotifyWatchResults) = params.NotifyWatchResults{
   256  			Results: []params.NotifyWatchResult{{
   257  				Error: &params.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, &params.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, &params.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 &params.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 &params.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  }