github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/discoverspaces/worker_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package discoverspaces_test
     5  
     6  import (
     7  	"sync/atomic"
     8  	"time"
     9  
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  	"gopkg.in/juju/names.v2"
    13  
    14  	"github.com/juju/juju/api"
    15  	apidiscoverspaces "github.com/juju/juju/api/discoverspaces"
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/environs"
    18  	"github.com/juju/juju/juju/testing"
    19  	"github.com/juju/juju/network"
    20  	"github.com/juju/juju/provider/dummy"
    21  	"github.com/juju/juju/state"
    22  	"github.com/juju/juju/state/stateenvirons"
    23  	coretesting "github.com/juju/juju/testing"
    24  	"github.com/juju/juju/worker"
    25  	"github.com/juju/juju/worker/discoverspaces"
    26  	"github.com/juju/juju/worker/gate"
    27  	"github.com/juju/juju/worker/workertest"
    28  )
    29  
    30  type WorkerSuite struct {
    31  	// TODO(fwereade): we *really* should not be using
    32  	// JujuConnSuite in new code.
    33  	testing.JujuConnSuite
    34  
    35  	APIConnection api.Connection
    36  	API           *checkingFacade
    37  
    38  	numCreateSpaceCalls uint32
    39  	numAddSubnetsCalls  uint32
    40  }
    41  
    42  type checkingFacade struct {
    43  	apidiscoverspaces.API
    44  
    45  	createSpacesCallback func()
    46  	addSubnetsCallback   func()
    47  }
    48  
    49  func (cf *checkingFacade) CreateSpaces(args params.CreateSpacesParams) (results params.ErrorResults, err error) {
    50  	if cf.createSpacesCallback != nil {
    51  		cf.createSpacesCallback()
    52  	}
    53  	return cf.API.CreateSpaces(args)
    54  }
    55  
    56  func (cf *checkingFacade) AddSubnets(args params.AddSubnetsParams) (params.ErrorResults, error) {
    57  	if cf.addSubnetsCallback != nil {
    58  		cf.addSubnetsCallback()
    59  	}
    60  	return cf.API.AddSubnets(args)
    61  }
    62  
    63  var _ = gc.Suite(&WorkerSuite{})
    64  
    65  func (s *WorkerSuite) SetUpTest(c *gc.C) {
    66  	s.JujuConnSuite.SetUpTest(c)
    67  
    68  	// Unbreak dummy provider methods.
    69  	s.AssertConfigParameterUpdated(c, "broken", "")
    70  
    71  	s.APIConnection, _ = s.OpenAPIAsNewMachine(c, state.JobManageModel)
    72  
    73  	realAPI := s.APIConnection.DiscoverSpaces()
    74  	s.API = &checkingFacade{
    75  		API: *realAPI,
    76  		createSpacesCallback: func() {
    77  			atomic.AddUint32(&s.numCreateSpaceCalls, 1)
    78  		},
    79  		addSubnetsCallback: func() {
    80  			atomic.AddUint32(&s.numAddSubnetsCalls, 1)
    81  		},
    82  	}
    83  }
    84  
    85  func (s *WorkerSuite) TearDownTest(c *gc.C) {
    86  	if s.APIConnection != nil {
    87  		c.Check(s.APIConnection.Close(), jc.ErrorIsNil)
    88  	}
    89  	s.JujuConnSuite.TearDownTest(c)
    90  }
    91  
    92  func (s *WorkerSuite) TestSupportsSpaceDiscoveryBroken(c *gc.C) {
    93  	s.AssertConfigParameterUpdated(c, "broken", "SupportsSpaceDiscovery")
    94  
    95  	worker, lock := s.startWorker(c)
    96  	err := workertest.CheckKilled(c, worker)
    97  	c.Assert(err, gc.ErrorMatches, "dummy.SupportsSpaceDiscovery is broken")
    98  
    99  	select {
   100  	case <-time.After(coretesting.ShortWait):
   101  	case <-lock.Unlocked():
   102  		c.Fatalf("gate unlocked despite worker failure")
   103  	}
   104  }
   105  
   106  func (s *WorkerSuite) TestSpacesBroken(c *gc.C) {
   107  	dummy.SetSupportsSpaceDiscovery(true)
   108  	s.AssertConfigParameterUpdated(c, "broken", "Spaces")
   109  
   110  	worker, lock := s.startWorker(c)
   111  	err := workertest.CheckKilled(c, worker)
   112  	c.Assert(err, gc.ErrorMatches, "dummy.Spaces is broken")
   113  
   114  	select {
   115  	case <-time.After(coretesting.ShortWait):
   116  	case <-lock.Unlocked():
   117  		c.Fatalf("gate unlocked despite worker failure")
   118  	}
   119  }
   120  
   121  func (s *WorkerSuite) TestWorkerSupportsNetworkingFalse(c *gc.C) {
   122  	// We set SupportsSpaceDiscovery to true so that spaces *would* be
   123  	// discovered if networking was supported. So we know that if they're
   124  	// discovered it must be because networking is not supported.
   125  	dummy.SetSupportsSpaceDiscovery(true)
   126  
   127  	// TODO(fwereade): monkey-patching remote packages is even worse
   128  	// than monkey-patching local packages, please don't do it.
   129  	noNetworking := func(environs.Environ) (environs.NetworkingEnviron, bool) {
   130  		return nil, false
   131  	}
   132  	s.PatchValue(&environs.SupportsNetworking, noNetworking)
   133  
   134  	s.unlockCheck(c, s.assertDiscoveredNoSpaces)
   135  }
   136  
   137  func (s *WorkerSuite) TestWorkerSupportsSpaceDiscoveryFalse(c *gc.C) {
   138  	s.unlockCheck(c, s.assertDiscoveredNoSpaces)
   139  }
   140  
   141  func (s *WorkerSuite) TestWorkerDiscoversSpaces(c *gc.C) {
   142  	dummy.SetSupportsSpaceDiscovery(true)
   143  	s.unlockCheck(c, func(*gc.C) {
   144  		s.assertDiscoveredSpaces(c)
   145  		s.assertNumCalls(c, 1, 1)
   146  	})
   147  }
   148  
   149  func (s *WorkerSuite) TestWorkerIdempotent(c *gc.C) {
   150  	dummy.SetSupportsSpaceDiscovery(true)
   151  	s.unlockCheck(c, s.assertDiscoveredSpaces)
   152  	s.unlockCheck(c, func(*gc.C) {
   153  		s.assertDiscoveredSpaces(c)
   154  		s.assertNumCalls(c, 2, 2)
   155  	})
   156  }
   157  
   158  func (s *WorkerSuite) TestWorkerIgnoresExistingSpacesAndSubnets(c *gc.C) {
   159  	dummy.SetSupportsSpaceDiscovery(true)
   160  	spaceTag := names.NewSpaceTag("foo")
   161  	args := params.CreateSpacesParams{
   162  		Spaces: []params.CreateSpaceParams{{
   163  			Public:     false,
   164  			SpaceTag:   spaceTag.String(),
   165  			ProviderId: "foo",
   166  		}}}
   167  	result, err := s.API.CreateSpaces(args)
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	c.Assert(result.Results, gc.HasLen, 1)
   170  	c.Assert(result.Results[0].Error, gc.IsNil)
   171  
   172  	subnetArgs := params.AddSubnetsParams{
   173  		Subnets: []params.AddSubnetParams{{
   174  			SubnetProviderId: "1",
   175  			SpaceTag:         spaceTag.String(),
   176  			Zones:            []string{"zone1"},
   177  		}}}
   178  	subnetResult, err := s.API.AddSubnets(subnetArgs)
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	c.Assert(subnetResult.Results, gc.HasLen, 1)
   181  	c.Assert(subnetResult.Results[0].Error, gc.IsNil)
   182  
   183  	s.unlockCheck(c, func(c *gc.C) {
   184  		spaces, err := s.State.AllSpaces()
   185  		c.Assert(err, jc.ErrorIsNil)
   186  		c.Assert(spaces, gc.HasLen, 5)
   187  	})
   188  }
   189  
   190  func (s *WorkerSuite) startWorker(c *gc.C) (worker.Worker, gate.Lock) {
   191  	// create fresh environ to see any injected broken-ness
   192  	environ, err := stateenvirons.GetNewEnvironFunc(environs.New)(s.State)
   193  	c.Assert(err, jc.ErrorIsNil)
   194  
   195  	lock := gate.NewLock()
   196  	worker, err := discoverspaces.NewWorker(discoverspaces.Config{
   197  		Facade:   s.API,
   198  		Environ:  environ,
   199  		NewName:  network.ConvertSpaceName,
   200  		Unlocker: lock,
   201  	})
   202  	c.Assert(err, jc.ErrorIsNil)
   203  	return worker, lock
   204  }
   205  
   206  func (s *WorkerSuite) unlockCheck(c *gc.C, check func(c *gc.C)) {
   207  	worker, lock := s.startWorker(c)
   208  	defer workertest.CleanKill(c, worker)
   209  	select {
   210  	case <-time.After(coretesting.LongWait):
   211  		c.Fatalf("discovery never completed")
   212  	case <-lock.Unlocked():
   213  		check(c)
   214  	}
   215  	workertest.CheckAlive(c, worker)
   216  }
   217  
   218  func (s *WorkerSuite) assertDiscoveredNoSpaces(c *gc.C) {
   219  	spaces, err := s.State.AllSpaces()
   220  	c.Assert(err, jc.ErrorIsNil)
   221  	c.Check(spaces, gc.HasLen, 0)
   222  }
   223  
   224  func (s *WorkerSuite) assertDiscoveredSpaces(c *gc.C) {
   225  	spaces, err := s.State.AllSpaces()
   226  	c.Assert(err, jc.ErrorIsNil)
   227  	c.Assert(spaces, gc.HasLen, 4)
   228  	expectedSpaces := []network.SpaceInfo{{
   229  		Name:       "foo",
   230  		ProviderId: network.Id("0"),
   231  		Subnets: []network.SubnetInfo{{
   232  			ProviderId:        network.Id("1"),
   233  			CIDR:              "192.168.1.0/24",
   234  			AvailabilityZones: []string{"zone1"},
   235  		}, {
   236  			ProviderId:        network.Id("2"),
   237  			CIDR:              "192.168.2.0/24",
   238  			AvailabilityZones: []string{"zone1"},
   239  		}}}, {
   240  		Name:       "another-foo-99",
   241  		ProviderId: network.Id("1"),
   242  		Subnets: []network.SubnetInfo{{
   243  			ProviderId:        network.Id("3"),
   244  			CIDR:              "192.168.3.0/24",
   245  			AvailabilityZones: []string{"zone1"},
   246  		}}}, {
   247  		Name:       "foo-2",
   248  		ProviderId: network.Id("2"),
   249  		Subnets: []network.SubnetInfo{{
   250  			ProviderId:        network.Id("4"),
   251  			CIDR:              "192.168.4.0/24",
   252  			AvailabilityZones: []string{"zone1"},
   253  		}}}, {
   254  		Name:       "empty",
   255  		ProviderId: network.Id("3"),
   256  		Subnets: []network.SubnetInfo{{
   257  			ProviderId:        network.Id("5"),
   258  			CIDR:              "192.168.5.0/24",
   259  			AvailabilityZones: []string{"zone1"},
   260  		}}}}
   261  	expectedSpaceMap := make(map[string]network.SpaceInfo)
   262  	for _, space := range expectedSpaces {
   263  		expectedSpaceMap[space.Name] = space
   264  	}
   265  	for _, space := range spaces {
   266  		expected, ok := expectedSpaceMap[space.Name()]
   267  		if !c.Check(ok, jc.IsTrue) {
   268  			continue
   269  		}
   270  		c.Check(space.ProviderId(), gc.Equals, expected.ProviderId)
   271  		subnets, err := space.Subnets()
   272  		if !c.Check(err, jc.ErrorIsNil) {
   273  			continue
   274  		}
   275  		if !c.Check(len(subnets), gc.Equals, len(expected.Subnets)) {
   276  			continue
   277  		}
   278  		for i, subnet := range subnets {
   279  			expectedSubnet := expected.Subnets[i]
   280  			c.Check(subnet.ProviderId(), gc.Equals, expectedSubnet.ProviderId)
   281  			c.Check([]string{subnet.AvailabilityZone()}, jc.DeepEquals, expectedSubnet.AvailabilityZones)
   282  			c.Check(subnet.CIDR(), gc.Equals, expectedSubnet.CIDR)
   283  		}
   284  	}
   285  }
   286  
   287  func (s *WorkerSuite) assertNumCalls(c *gc.C, expectedNumCreateSpaceCalls, expectedNumAddSubnetsCalls int) {
   288  	c.Check(atomic.LoadUint32(&s.numCreateSpaceCalls), gc.Equals, uint32(expectedNumCreateSpaceCalls))
   289  	c.Check(atomic.LoadUint32(&s.numAddSubnetsCalls), gc.Equals, uint32(expectedNumAddSubnetsCalls))
   290  }