github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/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  	"github.com/juju/testing"
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/apiserver/common"
    13  	"github.com/juju/juju/apiserver/machineundertaker"
    14  	"github.com/juju/juju/apiserver/params"
    15  	apiservertesting "github.com/juju/juju/apiserver/testing"
    16  	"github.com/juju/juju/network"
    17  	"github.com/juju/juju/state"
    18  )
    19  
    20  type undertakerSuite struct {
    21  	testing.IsolationSuite
    22  }
    23  
    24  var _ = gc.Suite(&undertakerSuite{})
    25  
    26  const (
    27  	uuid1 = "12345678-1234-1234-1234-123456789abc"
    28  	tag1  = "model-12345678-1234-1234-1234-123456789abc"
    29  	uuid2 = "12345678-1234-1234-1234-123456789abd"
    30  	tag2  = "model-12345678-1234-1234-1234-123456789abd"
    31  )
    32  
    33  func (*undertakerSuite) TestRequiresModelManager(c *gc.C) {
    34  	backend := &mockBackend{}
    35  	_, err := machineundertaker.NewAPI(
    36  		backend,
    37  		nil,
    38  		apiservertesting.FakeAuthorizer{EnvironManager: false},
    39  	)
    40  	c.Assert(err, gc.ErrorMatches, "permission denied")
    41  	_, err = machineundertaker.NewAPI(
    42  		backend,
    43  		nil,
    44  		apiservertesting.FakeAuthorizer{EnvironManager: true},
    45  	)
    46  	c.Assert(err, jc.ErrorIsNil)
    47  }
    48  
    49  func (*undertakerSuite) TestAllMachineRemovalsNoResults(c *gc.C) {
    50  	_, _, api := makeAPI(c, uuid1)
    51  	result := api.AllMachineRemovals(makeEntities(tag1))
    52  	c.Assert(result, gc.DeepEquals, params.EntitiesResults{
    53  		Results: []params.EntitiesResult{{}}, // So, one empty set of entities.
    54  	})
    55  }
    56  
    57  func (*undertakerSuite) TestAllMachineRemovalsError(c *gc.C) {
    58  	backend, _, api := makeAPI(c, uuid1)
    59  	backend.SetErrors(errors.New("I don't want to set the world on fire"))
    60  	result := api.AllMachineRemovals(makeEntities(tag1))
    61  	c.Assert(result.Results, gc.HasLen, 1)
    62  	c.Assert(result.Results[0].Error, gc.ErrorMatches, "I don't want to set the world on fire")
    63  	c.Assert(result.Results[0].Entities, jc.DeepEquals, []params.Entity{})
    64  }
    65  
    66  func (*undertakerSuite) TestAllMachineRemovalsRequiresModelTags(c *gc.C) {
    67  	_, _, api := makeAPI(c, uuid1)
    68  	results := api.AllMachineRemovals(makeEntities(tag1, "machine-0"))
    69  	c.Assert(results.Results, gc.HasLen, 2)
    70  	c.Assert(results.Results[0].Error, gc.IsNil)
    71  	c.Assert(results.Results[0].Entities, jc.DeepEquals, []params.Entity{})
    72  	c.Assert(results.Results[1].Error, gc.ErrorMatches, `"machine-0" is not a valid model tag`)
    73  	c.Assert(results.Results[1].Entities, jc.DeepEquals, []params.Entity{})
    74  }
    75  
    76  func (*undertakerSuite) TestAllMachineRemovalsChecksModelTag(c *gc.C) {
    77  	_, _, api := makeAPI(c, uuid1)
    78  	results := api.AllMachineRemovals(makeEntities(tag2))
    79  	c.Assert(results.Results, gc.HasLen, 1)
    80  	c.Assert(results.Results[0].Error, gc.ErrorMatches, "permission denied")
    81  	c.Assert(results.Results[0].Entities, gc.IsNil)
    82  }
    83  
    84  func (*undertakerSuite) TestAllMachineRemovals(c *gc.C) {
    85  	backend, _, api := makeAPI(c, uuid1)
    86  	backend.removals = []string{"0", "2"}
    87  
    88  	result := api.AllMachineRemovals(makeEntities(tag1))
    89  	c.Assert(result, gc.DeepEquals, makeEntitiesResults("machine-0", "machine-2"))
    90  }
    91  
    92  func (*undertakerSuite) TestGetMachineProviderInterfaceInfo(c *gc.C) {
    93  	backend, _, api := makeAPI(c, "")
    94  	backend.machines = map[string]*mockMachine{
    95  		"0": &mockMachine{
    96  			Stub: &testing.Stub{},
    97  			interfaceInfos: []network.ProviderInterfaceInfo{{
    98  				InterfaceName: "billy",
    99  				MACAddress:    "hexadecimal!",
   100  				ProviderId:    "a number",
   101  			}, {
   102  				InterfaceName: "lily",
   103  				MACAddress:    "octal?",
   104  				ProviderId:    "different number",
   105  			}}},
   106  		"2": &mockMachine{
   107  			Stub: &testing.Stub{},
   108  			interfaceInfos: []network.ProviderInterfaceInfo{{
   109  				InterfaceName: "gilly",
   110  				MACAddress:    "sexagesimal?!",
   111  				ProviderId:    "some number",
   112  			}},
   113  		},
   114  	}
   115  	backend.SetErrors(nil, errors.NotFoundf("no machine 100 fool!"))
   116  
   117  	args := makeEntities("machine-2", "machine-100", "machine-0", "machine-inv")
   118  	result := api.GetMachineProviderInterfaceInfo(args)
   119  
   120  	c.Assert(result, gc.DeepEquals, params.ProviderInterfaceInfoResults{
   121  		Results: []params.ProviderInterfaceInfoResult{{
   122  			MachineTag: "machine-2",
   123  			Interfaces: []params.ProviderInterfaceInfo{{
   124  				InterfaceName: "gilly",
   125  				MACAddress:    "sexagesimal?!",
   126  				ProviderId:    "some number",
   127  			}},
   128  		}, {
   129  			MachineTag: "machine-100",
   130  			Error: common.ServerError(
   131  				errors.NotFoundf("no machine 100 fool!"),
   132  			),
   133  		}, {
   134  			MachineTag: "machine-0",
   135  			Interfaces: []params.ProviderInterfaceInfo{{
   136  				InterfaceName: "billy",
   137  				MACAddress:    "hexadecimal!",
   138  				ProviderId:    "a number",
   139  			}, {
   140  				InterfaceName: "lily",
   141  				MACAddress:    "octal?",
   142  				ProviderId:    "different number",
   143  			}},
   144  		}, {
   145  			MachineTag: "machine-inv",
   146  			Error: common.ServerError(
   147  				errors.New(`"machine-inv" is not a valid machine tag`),
   148  			),
   149  		}},
   150  	})
   151  }
   152  
   153  func (*undertakerSuite) TestGetMachineProviderInterfaceInfoHandlesError(c *gc.C) {
   154  	backend, _, api := makeAPI(c, "")
   155  	backend.machines = map[string]*mockMachine{
   156  		"0": &mockMachine{Stub: backend.Stub},
   157  	}
   158  	backend.SetErrors(nil, errors.New("oops - problem getting interface infos"))
   159  	result := api.GetMachineProviderInterfaceInfo(makeEntities("machine-0"))
   160  
   161  	c.Assert(result.Results, gc.DeepEquals, []params.ProviderInterfaceInfoResult{{
   162  		MachineTag: "machine-0",
   163  		Error:      common.ServerError(errors.New("oops - problem getting interface infos")),
   164  	}})
   165  }
   166  
   167  func (*undertakerSuite) TestCompleteMachineRemovalsWithNonMachineTags(c *gc.C) {
   168  	_, _, api := makeAPI(c, "")
   169  	err := api.CompleteMachineRemovals(makeEntities("machine-2", "application-a1"))
   170  	c.Assert(err, gc.ErrorMatches, `"application-a1" is not a valid machine tag`)
   171  }
   172  
   173  func (*undertakerSuite) TestCompleteMachineRemovalsWithOtherError(c *gc.C) {
   174  	backend, _, api := makeAPI(c, "")
   175  	backend.SetErrors(errors.New("boom"))
   176  	err := api.CompleteMachineRemovals(makeEntities("machine-2"))
   177  	c.Assert(err, gc.ErrorMatches, "boom")
   178  }
   179  
   180  func (*undertakerSuite) TestCompleteMachineRemovals(c *gc.C) {
   181  	backend, _, api := makeAPI(c, "")
   182  	err := api.CompleteMachineRemovals(makeEntities("machine-2", "machine-52"))
   183  	c.Assert(err, jc.ErrorIsNil)
   184  	backend.CheckCallNames(c, "CompleteMachineRemovals")
   185  	callArgs := backend.Calls()[0].Args
   186  	c.Assert(len(callArgs), gc.Equals, 1)
   187  	values, ok := callArgs[0].([]string)
   188  	c.Assert(ok, jc.IsTrue)
   189  	c.Assert(values, gc.DeepEquals, []string{"2", "52"})
   190  }
   191  
   192  func (*undertakerSuite) TestWatchMachineRemovals(c *gc.C) {
   193  	backend, res, api := makeAPI(c, uuid1)
   194  
   195  	result := api.WatchMachineRemovals(makeEntities(tag1))
   196  	c.Assert(result.Results, gc.HasLen, 1)
   197  	c.Assert(res.Get(result.Results[0].NotifyWatcherId), gc.NotNil)
   198  	c.Assert(result.Results[0].Error, gc.IsNil)
   199  	backend.CheckCallNames(c, "WatchMachineRemovals")
   200  }
   201  
   202  func (*undertakerSuite) TestWatchMachineRemovalsPermissionError(c *gc.C) {
   203  	_, _, api := makeAPI(c, uuid1)
   204  	result := api.WatchMachineRemovals(makeEntities(tag2))
   205  	c.Assert(result.Results, gc.HasLen, 1)
   206  	c.Assert(result.Results[0].Error, gc.ErrorMatches, "permission denied")
   207  }
   208  
   209  func (*undertakerSuite) TestWatchMachineRemovalsError(c *gc.C) {
   210  	backend, _, api := makeAPI(c, uuid1)
   211  	backend.watcherBlowsUp = true
   212  	backend.SetErrors(errors.New("oh no!"))
   213  
   214  	result := api.WatchMachineRemovals(makeEntities(tag1))
   215  	c.Assert(result.Results, gc.HasLen, 1)
   216  	c.Assert(result.Results[0].Error, gc.ErrorMatches, "oh no!")
   217  	c.Assert(result.Results[0].NotifyWatcherId, gc.Equals, "")
   218  	backend.CheckCallNames(c, "WatchMachineRemovals")
   219  }
   220  
   221  func makeAPI(c *gc.C, modelUUID string) (*mockBackend, *common.Resources, *machineundertaker.API) {
   222  	backend := &mockBackend{Stub: &testing.Stub{}}
   223  	res := common.NewResources()
   224  	api, err := machineundertaker.NewAPI(
   225  		backend,
   226  		res,
   227  		apiservertesting.FakeAuthorizer{
   228  			EnvironManager: true,
   229  			ModelUUID:      modelUUID,
   230  		},
   231  	)
   232  	c.Assert(err, jc.ErrorIsNil)
   233  	return backend, res, api
   234  }
   235  
   236  func makeEntities(tags ...string) params.Entities {
   237  	return params.Entities{Entities: makeEntitySlice(tags...)}
   238  }
   239  
   240  func makeEntitySlice(tags ...string) []params.Entity {
   241  	entities := make([]params.Entity, len(tags))
   242  	for i := range tags {
   243  		entities[i] = params.Entity{Tag: tags[i]}
   244  	}
   245  	return entities
   246  }
   247  
   248  func makeEntitiesResults(tags ...string) params.EntitiesResults {
   249  	return params.EntitiesResults{
   250  		Results: []params.EntitiesResult{{
   251  			Entities: makeEntitySlice(tags...),
   252  		}},
   253  	}
   254  }
   255  
   256  type mockBackend struct {
   257  	*testing.Stub
   258  
   259  	removals       []string
   260  	machines       map[string]*mockMachine
   261  	watcherBlowsUp bool
   262  }
   263  
   264  func (b *mockBackend) AllMachineRemovals() ([]string, error) {
   265  	b.AddCall("AllMachineRemovals")
   266  	return b.removals, b.NextErr()
   267  }
   268  
   269  func (b *mockBackend) CompleteMachineRemovals(machineIDs ...string) error {
   270  	b.AddCall("CompleteMachineRemovals", machineIDs)
   271  	return b.NextErr()
   272  }
   273  
   274  func (b *mockBackend) WatchMachineRemovals() state.NotifyWatcher {
   275  	b.AddCall("WatchMachineRemovals")
   276  	watcher := &mockWatcher{backend: b, out: make(chan struct{}, 1)}
   277  	if b.watcherBlowsUp {
   278  		close(watcher.out)
   279  	} else {
   280  		watcher.out <- struct{}{}
   281  	}
   282  	return watcher
   283  }
   284  
   285  func (b *mockBackend) Machine(id string) (machineundertaker.Machine, error) {
   286  	b.AddCall("Machine", id)
   287  	return b.machines[id], b.NextErr()
   288  }
   289  
   290  type mockMachine struct {
   291  	*testing.Stub
   292  	interfaceInfos []network.ProviderInterfaceInfo
   293  }
   294  
   295  func (m *mockMachine) AllProviderInterfaceInfos() ([]network.ProviderInterfaceInfo, error) {
   296  	m.AddCall("AllProviderInterfaceInfos")
   297  	err := m.NextErr()
   298  	if err != nil {
   299  		return nil, err
   300  	}
   301  	return m.interfaceInfos, err
   302  }
   303  
   304  type mockWatcher struct {
   305  	state.NotifyWatcher
   306  
   307  	backend *mockBackend
   308  	out     chan struct{}
   309  }
   310  
   311  func (w *mockWatcher) Changes() <-chan struct{} {
   312  	return w.out
   313  }
   314  
   315  func (w *mockWatcher) Err() error {
   316  	return w.backend.NextErr()
   317  }