github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/provider/common/availabilityzones_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package common_test
     5  
     6  import (
     7  	"fmt"
     8  
     9  	jc "github.com/juju/testing/checkers"
    10  	gc "gopkg.in/check.v1"
    11  
    12  	"github.com/juju/juju/environs"
    13  	"github.com/juju/juju/instance"
    14  	"github.com/juju/juju/provider/common"
    15  	coretesting "github.com/juju/juju/testing"
    16  )
    17  
    18  type AvailabilityZoneSuite struct {
    19  	coretesting.FakeJujuHomeSuite
    20  	env mockZonedEnviron
    21  }
    22  
    23  var _ = gc.Suite(&AvailabilityZoneSuite{})
    24  
    25  func (s *AvailabilityZoneSuite) SetUpSuite(c *gc.C) {
    26  	s.FakeJujuHomeSuite.SetUpSuite(c)
    27  
    28  	allInstances := make([]instance.Instance, 3)
    29  	for i := range allInstances {
    30  		allInstances[i] = &mockInstance{id: fmt.Sprintf("inst%d", i)}
    31  	}
    32  	s.env.allInstances = func() ([]instance.Instance, error) {
    33  		return allInstances, nil
    34  	}
    35  
    36  	availabilityZones := make([]common.AvailabilityZone, 3)
    37  	for i := range availabilityZones {
    38  		availabilityZones[i] = &mockAvailabilityZone{
    39  			name:      fmt.Sprintf("az%d", i),
    40  			available: i > 0,
    41  		}
    42  	}
    43  	s.env.availabilityZones = func() ([]common.AvailabilityZone, error) {
    44  		return availabilityZones, nil
    45  	}
    46  }
    47  
    48  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsAllInstances(c *gc.C) {
    49  	var called int
    50  	s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) {
    51  		c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"})
    52  		called++
    53  		return []string{"az0", "az1", "az2"}, nil
    54  	})
    55  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil)
    56  	c.Assert(called, gc.Equals, 1)
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	// az0 is unavailable, so az1 and az2 come out as equal best;
    59  	// az1 comes first due to lexicographical ordering on the name.
    60  	c.Assert(zoneInstances, gc.DeepEquals, []common.AvailabilityZoneInstances{{
    61  		ZoneName:  "az1",
    62  		Instances: []instance.Id{"inst1"},
    63  	}, {
    64  		ZoneName:  "az2",
    65  		Instances: []instance.Id{"inst2"},
    66  	}})
    67  }
    68  
    69  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsAllInstancesErrors(c *gc.C) {
    70  	resultErr := fmt.Errorf("oh noes")
    71  	s.PatchValue(&s.env.allInstances, func() ([]instance.Instance, error) {
    72  		return nil, resultErr
    73  	})
    74  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil)
    75  	c.Assert(err, gc.Equals, resultErr)
    76  	c.Assert(zoneInstances, gc.HasLen, 0)
    77  }
    78  
    79  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsPartialInstances(c *gc.C) {
    80  	var called int
    81  	s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) {
    82  		c.Assert(ids, gc.DeepEquals, []instance.Id{"nichts", "inst1", "null", "inst2"})
    83  		called++
    84  		return []string{"", "az1", "", "az1"}, environs.ErrPartialInstances
    85  	})
    86  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, []instance.Id{"nichts", "inst1", "null", "inst2"})
    87  	c.Assert(called, gc.Equals, 1)
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	// az2 has fewer instances, so comes first.
    90  	c.Assert(zoneInstances, gc.DeepEquals, []common.AvailabilityZoneInstances{{
    91  		ZoneName: "az2",
    92  	}, {
    93  		ZoneName:  "az1",
    94  		Instances: []instance.Id{"inst1", "inst2"},
    95  	}})
    96  }
    97  
    98  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsInstanceAvailabilityZonesErrors(c *gc.C) {
    99  	returnErr := fmt.Errorf("whatever")
   100  	var called int
   101  	s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) {
   102  		called++
   103  		return nil, returnErr
   104  	})
   105  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil)
   106  	c.Assert(called, gc.Equals, 1)
   107  	c.Assert(err, gc.Equals, returnErr)
   108  	c.Assert(zoneInstances, gc.HasLen, 0)
   109  }
   110  
   111  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsInstanceAvailabilityZonesNoInstances(c *gc.C) {
   112  	var called int
   113  	s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) {
   114  		called++
   115  		return nil, environs.ErrNoInstances
   116  	})
   117  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil)
   118  	c.Assert(called, gc.Equals, 1)
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	c.Assert(zoneInstances, gc.HasLen, 2)
   121  }
   122  
   123  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsNoZones(c *gc.C) {
   124  	var calls []string
   125  	s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) {
   126  		c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"})
   127  		calls = append(calls, "InstanceAvailabilityZoneNames")
   128  		return []string{"", "", ""}, nil
   129  	})
   130  	s.PatchValue(&s.env.availabilityZones, func() ([]common.AvailabilityZone, error) {
   131  		calls = append(calls, "AvailabilityZones")
   132  		return []common.AvailabilityZone{}, nil
   133  	})
   134  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil)
   135  	c.Assert(calls, gc.DeepEquals, []string{"InstanceAvailabilityZoneNames", "AvailabilityZones"})
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	c.Assert(zoneInstances, gc.HasLen, 0)
   138  }
   139  
   140  func (s *AvailabilityZoneSuite) TestAvailabilityZoneAllocationsErrors(c *gc.C) {
   141  	var calls []string
   142  	s.PatchValue(&s.env.instanceAvailabilityZoneNames, func(ids []instance.Id) ([]string, error) {
   143  		c.Assert(ids, gc.DeepEquals, []instance.Id{"inst0", "inst1", "inst2"})
   144  		calls = append(calls, "InstanceAvailabilityZoneNames")
   145  		return []string{"", "", ""}, nil
   146  	})
   147  	resultErr := fmt.Errorf("u can haz no az")
   148  	s.PatchValue(&s.env.availabilityZones, func() ([]common.AvailabilityZone, error) {
   149  		calls = append(calls, "AvailabilityZones")
   150  		return nil, resultErr
   151  	})
   152  	zoneInstances, err := common.AvailabilityZoneAllocations(&s.env, nil)
   153  	c.Assert(calls, gc.DeepEquals, []string{"InstanceAvailabilityZoneNames", "AvailabilityZones"})
   154  	c.Assert(err, gc.Equals, resultErr)
   155  	c.Assert(zoneInstances, gc.HasLen, 0)
   156  }
   157  
   158  func (s *AvailabilityZoneSuite) TestDistributeInstancesGroup(c *gc.C) {
   159  	expectedGroup := []instance.Id{"0", "1", "2"}
   160  	var called bool
   161  	s.PatchValue(common.InternalAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) ([]common.AvailabilityZoneInstances, error) {
   162  		c.Assert(group, gc.DeepEquals, expectedGroup)
   163  		called = true
   164  		return nil, nil
   165  	})
   166  	common.DistributeInstances(&s.env, nil, expectedGroup)
   167  	c.Assert(called, jc.IsTrue)
   168  }
   169  
   170  func (s *AvailabilityZoneSuite) TestDistributeInstancesGroupErrors(c *gc.C) {
   171  	resultErr := fmt.Errorf("whatever")
   172  	s.PatchValue(common.InternalAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) ([]common.AvailabilityZoneInstances, error) {
   173  		return nil, resultErr
   174  	})
   175  	_, err := common.DistributeInstances(&s.env, nil, nil)
   176  	c.Assert(err, gc.Equals, resultErr)
   177  }
   178  
   179  func (s *AvailabilityZoneSuite) TestDistributeInstances(c *gc.C) {
   180  	var zoneInstances []common.AvailabilityZoneInstances
   181  	s.PatchValue(common.InternalAvailabilityZoneAllocations, func(_ common.ZonedEnviron, group []instance.Id) ([]common.AvailabilityZoneInstances, error) {
   182  		return zoneInstances, nil
   183  	})
   184  
   185  	type distributeInstancesTest struct {
   186  		zoneInstances []common.AvailabilityZoneInstances
   187  		candidates    []instance.Id
   188  		eligible      []instance.Id
   189  	}
   190  
   191  	tests := []distributeInstancesTest{{
   192  		zoneInstances: []common.AvailabilityZoneInstances{{
   193  			ZoneName:  "az0",
   194  			Instances: []instance.Id{"i0"},
   195  		}, {
   196  			ZoneName:  "az1",
   197  			Instances: []instance.Id{"i1"},
   198  		}, {
   199  			ZoneName:  "az2",
   200  			Instances: []instance.Id{"i2"},
   201  		}},
   202  		candidates: []instance.Id{"i2", "i3", "i4"},
   203  		eligible:   []instance.Id{"i2"},
   204  	}, {
   205  		zoneInstances: []common.AvailabilityZoneInstances{{
   206  			ZoneName:  "az0",
   207  			Instances: []instance.Id{"i0"},
   208  		}, {
   209  			ZoneName:  "az1",
   210  			Instances: []instance.Id{"i1"},
   211  		}, {
   212  			ZoneName:  "az2",
   213  			Instances: []instance.Id{"i2"},
   214  		}},
   215  		candidates: []instance.Id{"i0", "i1", "i2"},
   216  		eligible:   []instance.Id{"i0", "i1", "i2"},
   217  	}, {
   218  		zoneInstances: []common.AvailabilityZoneInstances{{
   219  			ZoneName:  "az0",
   220  			Instances: []instance.Id{"i0"},
   221  		}, {
   222  			ZoneName:  "az1",
   223  			Instances: []instance.Id{"i1"},
   224  		}, {
   225  			ZoneName:  "az2",
   226  			Instances: []instance.Id{"i2"},
   227  		}},
   228  		candidates: []instance.Id{"i3", "i4", "i5"},
   229  		eligible:   []instance.Id{},
   230  	}, {
   231  		zoneInstances: []common.AvailabilityZoneInstances{{
   232  			ZoneName:  "az0",
   233  			Instances: []instance.Id{"i0"},
   234  		}, {
   235  			ZoneName:  "az1",
   236  			Instances: []instance.Id{"i1"},
   237  		}, {
   238  			ZoneName:  "az2",
   239  			Instances: []instance.Id{"i2"},
   240  		}},
   241  		candidates: []instance.Id{},
   242  		eligible:   []instance.Id{},
   243  	}, {
   244  		zoneInstances: []common.AvailabilityZoneInstances{},
   245  		candidates:    []instance.Id{"i0"},
   246  		eligible:      []instance.Id{},
   247  	}}
   248  
   249  	for i, test := range tests {
   250  		c.Logf("test %d", i)
   251  		zoneInstances = test.zoneInstances
   252  		eligible, err := common.DistributeInstances(&s.env, test.candidates, nil)
   253  		c.Assert(err, jc.ErrorIsNil)
   254  		c.Assert(eligible, jc.SameContents, test.eligible)
   255  	}
   256  }