Permalink
Switch branches/tags
Find file
Fetching contributors…
Cannot retrieve contributors at this time
275 lines (216 sloc) 10 KB
// Copyright 2014 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package state_test
import (
"fmt"
"github.com/juju/errors"
jc "github.com/juju/testing/checkers"
gc "gopkg.in/check.v1"
"github.com/juju/juju/state"
)
type SubnetSuite struct {
ConnSuite
}
var _ = gc.Suite(&SubnetSuite{})
func (s *SubnetSuite) TestAddSubnetSucceedsWithFullyPopulatedInfo(c *gc.C) {
subnetInfo := state.SubnetInfo{
ProviderId: "foo",
CIDR: "192.168.1.0/24",
VLANTag: 79,
AvailabilityZone: "Timbuktu",
SpaceName: "foo",
}
subnet, err := s.State.AddSubnet(subnetInfo)
c.Assert(err, jc.ErrorIsNil)
s.assertSubnetMatchesInfo(c, subnet, subnetInfo)
// check it's been stored in state by fetching it back again
subnetFromDB, err := s.State.Subnet("192.168.1.0/24")
c.Assert(err, jc.ErrorIsNil)
s.assertSubnetMatchesInfo(c, subnetFromDB, subnetInfo)
}
func (s *SubnetSuite) assertSubnetMatchesInfo(c *gc.C, subnet *state.Subnet, info state.SubnetInfo) {
c.Assert(subnet.ProviderId(), gc.Equals, info.ProviderId)
c.Assert(subnet.CIDR(), gc.Equals, info.CIDR)
c.Assert(subnet.VLANTag(), gc.Equals, info.VLANTag)
c.Assert(subnet.AvailabilityZone(), gc.Equals, info.AvailabilityZone)
c.Assert(subnet.String(), gc.Equals, info.CIDR)
c.Assert(subnet.GoString(), gc.Equals, info.CIDR)
c.Assert(subnet.SpaceName(), gc.Equals, info.SpaceName)
}
func (s *SubnetSuite) TestAddSubnetFailsWithEmptyCIDR(c *gc.C) {
subnetInfo := state.SubnetInfo{}
s.assertAddSubnetForInfoFailsWithSuffix(c, subnetInfo, "missing CIDR")
}
func (s *SubnetSuite) assertAddSubnetForInfoFailsWithSuffix(c *gc.C, subnetInfo state.SubnetInfo, errorSuffix string) error {
subnet, err := s.State.AddSubnet(subnetInfo)
errorMessage := fmt.Sprintf("adding subnet %q: %s", subnetInfo.CIDR, errorSuffix)
c.Assert(err, gc.ErrorMatches, errorMessage)
c.Assert(subnet, gc.IsNil)
return err
}
func (s *SubnetSuite) TestAddSubnetFailsWithInvalidCIDR(c *gc.C) {
subnetInfo := state.SubnetInfo{CIDR: "foobar"}
s.assertAddSubnetForInfoFailsWithSuffix(c, subnetInfo, "invalid CIDR address: foobar")
}
func (s *SubnetSuite) TestAddSubnetFailsWithOutOfRangeVLANTag(c *gc.C) {
subnetInfo := state.SubnetInfo{CIDR: "192.168.0.1/24", VLANTag: 4095}
s.assertAddSubnetForInfoFailsWithSuffix(c, subnetInfo, "invalid VLAN tag 4095: must be between 0 and 4094")
}
func (s *SubnetSuite) TestAddSubnetFailsWithAlreadyExistsForDuplicateCIDRInSameModel(c *gc.C) {
subnetInfo := state.SubnetInfo{CIDR: "192.168.0.1/24"}
subnet, err := s.State.AddSubnet(subnetInfo)
c.Assert(err, jc.ErrorIsNil)
s.assertSubnetMatchesInfo(c, subnet, subnetInfo)
err = s.assertAddSubnetForInfoFailsWithSuffix(c, subnetInfo, `subnet "192.168.0.1/24" already exists`)
c.Assert(err, jc.Satisfies, errors.IsAlreadyExists)
}
func (s *SubnetSuite) TestAddSubnetSucceedsForDuplicateCIDRInDifferentModels(c *gc.C) {
subnetInfo1 := state.SubnetInfo{CIDR: "192.168.0.1/24"}
subnetInfo2 := state.SubnetInfo{CIDR: "10.0.0.0/24"}
subnet1State := s.NewStateForModelNamed(c, "other-model")
subnet1, subnet2 := s.addTwoSubnetsInDifferentModelsAssertSuccessAndReturnBoth(c, subnetInfo1, subnetInfo2, subnet1State)
s.assertSubnetMatchesInfo(c, subnet1, subnetInfo1)
s.assertSubnetMatchesInfo(c, subnet2, subnetInfo2)
}
func (s *SubnetSuite) addTwoSubnetsInDifferentModelsAssertSuccessAndReturnBoth(c *gc.C, info1, info2 state.SubnetInfo, otherState *state.State) (*state.Subnet, *state.Subnet) {
subnet1, err := otherState.AddSubnet(info1)
c.Assert(err, jc.ErrorIsNil)
subnet2, err := s.State.AddSubnet(info2)
c.Assert(err, jc.ErrorIsNil)
return subnet1, subnet2
}
func (s *SubnetSuite) TestAddSubnetFailsWhenProviderIdNotUniqueInSameModel(c *gc.C) {
subnetInfo1 := state.SubnetInfo{CIDR: "192.168.0.1/24", ProviderId: "foo"}
subnetInfo2 := state.SubnetInfo{CIDR: "10.0.0.0/24", ProviderId: "foo"}
s.addTwoSubnetsAndAssertSecondFailsWithSuffix(c, subnetInfo1, subnetInfo2, `ProviderId "foo" not unique`)
}
func (s *SubnetSuite) addTwoSubnetsAndAssertSecondFailsWithSuffix(c *gc.C, info1, info2 state.SubnetInfo, errorSuffix string) {
s.addTwoSubnetsInDifferentModelsAndAssertSecondFailsWithSuffix(c, info1, info2, s.State, errorSuffix)
}
func (s *SubnetSuite) addTwoSubnetsInDifferentModelsAndAssertSecondFailsWithSuffix(c *gc.C, info1, info2 state.SubnetInfo, otherState *state.State, errorSuffix string) {
_, err := otherState.AddSubnet(info1)
c.Assert(err, jc.ErrorIsNil)
s.assertAddSubnetForInfoFailsWithSuffix(c, info2, errorSuffix)
}
func (s *SubnetSuite) TestAddSubnetSucceedsWhenProviderIdNotUniqueInDifferentModels(c *gc.C) {
subnetInfo1 := state.SubnetInfo{CIDR: "192.168.0.1/24", ProviderId: "foo"}
subnetInfo2 := state.SubnetInfo{CIDR: "10.0.0.0/24", ProviderId: "foo"}
subnet1State := s.NewStateForModelNamed(c, "other-model")
subnet1, subnet2 := s.addTwoSubnetsInDifferentModelsAssertSuccessAndReturnBoth(c, subnetInfo1, subnetInfo2, subnet1State)
s.assertSubnetMatchesInfo(c, subnet1, subnetInfo1)
s.assertSubnetMatchesInfo(c, subnet2, subnetInfo2)
}
func (s *SubnetSuite) TestAddSubnetSucceedsForDifferentCIDRsAndEmptyProviderIdInSameModel(c *gc.C) {
subnetInfo1 := state.SubnetInfo{CIDR: "192.168.0.1/24", ProviderId: ""}
subnetInfo2 := state.SubnetInfo{CIDR: "10.0.0.0/24", ProviderId: ""}
subnet1, subnet2 := s.addTwoSubnetsAssertSuccessAndReturnBoth(c, subnetInfo1, subnetInfo2)
s.assertSubnetMatchesInfo(c, subnet1, subnetInfo1)
s.assertSubnetMatchesInfo(c, subnet2, subnetInfo2)
}
func (s *SubnetSuite) addTwoSubnetsAssertSuccessAndReturnBoth(c *gc.C, info1, info2 state.SubnetInfo) (*state.Subnet, *state.Subnet) {
return s.addTwoSubnetsInDifferentModelsAssertSuccessAndReturnBoth(c, info1, info2, s.State)
}
func (s *SubnetSuite) TestAddSubnetSucceedsForDifferentCIDRsAndEmptyProviderIdInDifferentModels(c *gc.C) {
subnetInfo1 := state.SubnetInfo{CIDR: "192.168.0.1/24", ProviderId: ""}
subnetInfo2 := state.SubnetInfo{CIDR: "10.0.0.0/24", ProviderId: ""}
subnet1State := s.NewStateForModelNamed(c, "other-model")
subnet1, subnet2 := s.addTwoSubnetsInDifferentModelsAssertSuccessAndReturnBoth(c, subnetInfo1, subnetInfo2, subnet1State)
s.assertSubnetMatchesInfo(c, subnet1, subnetInfo1)
s.assertSubnetMatchesInfo(c, subnet2, subnetInfo2)
}
func (s *SubnetSuite) TestEnsureDeadSetsLifeToDeadWhenAlive(c *gc.C) {
subnet := s.addAliveSubnet(c, "192.168.0.1/24")
s.ensureDeadAndAssertLifeIsDead(c, subnet)
s.refreshAndAssertSubnetLifeIs(c, subnet, state.Dead)
}
func (s *SubnetSuite) addAliveSubnet(c *gc.C, cidr string) *state.Subnet {
subnetInfo := state.SubnetInfo{CIDR: cidr}
subnet, err := s.State.AddSubnet(subnetInfo)
c.Assert(err, jc.ErrorIsNil)
c.Assert(subnet.Life(), gc.Equals, state.Alive)
return subnet
}
func (s *SubnetSuite) ensureDeadAndAssertLifeIsDead(c *gc.C, subnet *state.Subnet) {
err := subnet.EnsureDead()
c.Assert(err, jc.ErrorIsNil)
c.Assert(subnet.Life(), gc.Equals, state.Dead)
}
func (s *SubnetSuite) refreshAndAssertSubnetLifeIs(c *gc.C, subnet *state.Subnet, expectedLife state.Life) {
err := subnet.Refresh()
c.Assert(err, jc.ErrorIsNil)
c.Assert(subnet.Life(), gc.Equals, expectedLife)
}
func (s *SubnetSuite) TestEnsureDeadSetsLifeToDeadWhenNotAlive(c *gc.C) {
subnet := s.addAliveSubnet(c, "192.168.0.1/24")
s.ensureDeadAndAssertLifeIsDead(c, subnet)
s.ensureDeadAndAssertLifeIsDead(c, subnet)
}
func (s *SubnetSuite) TestRemoveFailsIfStillAlive(c *gc.C) {
subnet := s.addAliveSubnet(c, "192.168.0.1/24")
err := subnet.Remove()
c.Assert(err, gc.ErrorMatches, `cannot remove subnet "192.168.0.1/24": subnet is not dead`)
s.refreshAndAssertSubnetLifeIs(c, subnet, state.Alive)
}
func (s *SubnetSuite) TestRemoveSucceedsWhenSubnetIsNotAlive(c *gc.C) {
subnet := s.addAliveSubnet(c, "192.168.0.1/24")
s.ensureDeadAndAssertLifeIsDead(c, subnet)
s.removeSubnetAndAssertNotFound(c, subnet)
}
func (s *SubnetSuite) removeSubnetAndAssertNotFound(c *gc.C, subnet *state.Subnet) {
err := subnet.Remove()
c.Assert(err, jc.ErrorIsNil)
s.assertSubnetWithCIDRNotFound(c, subnet.CIDR())
}
func (s *SubnetSuite) assertSubnetWithCIDRNotFound(c *gc.C, cidr string) {
_, err := s.State.Subnet(cidr)
s.assertSubnetNotFoundError(c, err)
}
func (s *SubnetSuite) assertSubnetNotFoundError(c *gc.C, err error) {
c.Assert(err, gc.ErrorMatches, "subnet .* not found")
c.Assert(err, jc.Satisfies, errors.IsNotFound)
}
func (s *SubnetSuite) TestRemoveSucceedsWhenCalledTwice(c *gc.C) {
subnet := s.addAliveSubnet(c, "192.168.0.1/24")
s.ensureDeadAndAssertLifeIsDead(c, subnet)
s.removeSubnetAndAssertNotFound(c, subnet)
err := subnet.Remove()
c.Assert(err, gc.ErrorMatches, `cannot remove subnet "192.168.0.1/24": not found or not dead`)
}
func (s *SubnetSuite) TestRefreshUpdatesStaleDocData(c *gc.C) {
subnet := s.addAliveSubnet(c, "fc00::/64")
subnetCopy, err := s.State.Subnet("fc00::/64")
c.Assert(err, jc.ErrorIsNil)
s.ensureDeadAndAssertLifeIsDead(c, subnet)
c.Assert(subnetCopy.Life(), gc.Equals, state.Alive)
err = subnetCopy.Refresh()
c.Assert(err, jc.ErrorIsNil)
c.Assert(subnetCopy.Life(), gc.Equals, state.Dead)
}
func (s *SubnetSuite) TestRefreshFailsWithNotFoundWhenRemoved(c *gc.C) {
subnet := s.addAliveSubnet(c, "192.168.1.0/24")
s.ensureDeadAndAssertLifeIsDead(c, subnet)
s.removeSubnetAndAssertNotFound(c, subnet)
err := subnet.Refresh()
s.assertSubnetNotFoundError(c, err)
}
func (s *SubnetSuite) TestAllSubnets(c *gc.C) {
subnetInfos := []state.SubnetInfo{
{CIDR: "192.168.1.0/24"},
{CIDR: "8.8.8.0/24", SpaceName: "bar"},
{CIDR: "10.0.2.0/24", ProviderId: "foo"},
{CIDR: "2001:db8::/64", AvailabilityZone: "zone1"},
}
for _, info := range subnetInfos {
_, err := s.State.AddSubnet(info)
c.Assert(err, jc.ErrorIsNil)
}
subnets, err := s.State.AllSubnets()
c.Assert(err, jc.ErrorIsNil)
c.Assert(subnets, gc.HasLen, len(subnetInfos))
for i, subnet := range subnets {
c.Assert(subnet.CIDR(), gc.Equals, subnetInfos[i].CIDR)
c.Assert(subnet.ProviderId(), gc.Equals, subnetInfos[i].ProviderId)
c.Assert(subnet.SpaceName(), gc.Equals, subnetInfos[i].SpaceName)
c.Assert(subnet.AvailabilityZone(), gc.Equals, subnetInfos[i].AvailabilityZone)
}
}