github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/core/network/space_test.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package network_test
     5  
     6  import (
     7  	"github.com/juju/collections/set"
     8  	"github.com/juju/errors"
     9  	"github.com/juju/testing"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/core/network"
    14  )
    15  
    16  type spaceSuite struct {
    17  	testing.IsolationSuite
    18  
    19  	spaces network.SpaceInfos
    20  }
    21  
    22  var _ = gc.Suite(&spaceSuite{})
    23  
    24  func (s *spaceSuite) SetUpTest(c *gc.C) {
    25  	s.spaces = network.SpaceInfos{
    26  		{ID: "1", Name: "space1", Subnets: []network.SubnetInfo{{ID: "11", CIDR: "10.0.0.0/24"}}},
    27  		{ID: "2", Name: "space2", Subnets: []network.SubnetInfo{{ID: "12", CIDR: "10.0.1.0/24"}}},
    28  		{ID: "3", Name: "space3", Subnets: []network.SubnetInfo{{ID: "13", CIDR: "10.0.2.0/24"}}},
    29  	}
    30  }
    31  
    32  func (s *spaceSuite) TestString(c *gc.C) {
    33  	result := s.spaces.String()
    34  	c.Assert(result, gc.Equals, `"space1", "space2", "space3"`)
    35  }
    36  
    37  func (s *spaceSuite) TestGetByName(c *gc.C) {
    38  	c.Assert(s.spaces.GetByName("space1"), gc.NotNil)
    39  	c.Assert(s.spaces.GetByName("space666"), gc.IsNil)
    40  }
    41  
    42  func (s *spaceSuite) TestGetByID(c *gc.C) {
    43  	c.Assert(s.spaces.GetByID("1"), gc.NotNil)
    44  	c.Assert(s.spaces.GetByID("999"), gc.IsNil)
    45  }
    46  
    47  func (s *spaceSuite) TestContainsName(c *gc.C) {
    48  	c.Assert(s.spaces.ContainsName("space3"), jc.IsTrue)
    49  	c.Assert(s.spaces.ContainsName("space666"), jc.IsFalse)
    50  }
    51  
    52  func (s *spaceSuite) TestMinus(c *gc.C) {
    53  	infos := network.SpaceInfos{
    54  		{ID: "2", Name: "space2"},
    55  		{ID: "3", Name: "space3"},
    56  	}
    57  	result := s.spaces.Minus(infos)
    58  	c.Assert(result, gc.DeepEquals, network.SpaceInfos{s.spaces[0]})
    59  }
    60  
    61  func (s *spaceSuite) TestMinusNoDiff(c *gc.C) {
    62  	infos := network.SpaceInfos{
    63  		{ID: "1", Name: "space1"},
    64  		{ID: "2", Name: "space2"},
    65  		{ID: "3", Name: "space3"},
    66  	}
    67  	result := s.spaces.Minus(infos)
    68  	c.Assert(result, gc.DeepEquals, network.SpaceInfos{})
    69  }
    70  
    71  func (s *spaceSuite) TestInferSpaceFromAddress(c *gc.C) {
    72  	queries := map[string]network.SpaceName{
    73  		"10.0.0.42": "space1",
    74  		"10.0.1.1":  "space2",
    75  		"10.0.2.99": "space3",
    76  	}
    77  
    78  	for addr, expSpaceName := range queries {
    79  		si, err := s.spaces.InferSpaceFromAddress(addr)
    80  		c.Assert(err, jc.ErrorIsNil, gc.Commentf("infer space for address %q", addr))
    81  		c.Assert(si.Name, gc.Equals, expSpaceName, gc.Commentf("infer space for address %q", addr))
    82  	}
    83  
    84  	// Check that CIDR collisions are detected
    85  	s.spaces = append(
    86  		s.spaces,
    87  		network.SpaceInfo{ID: "-3", Name: "inverse", Subnets: []network.SubnetInfo{{CIDR: "10.0.2.0/24"}}},
    88  	)
    89  
    90  	_, err := s.spaces.InferSpaceFromAddress("10.0.2.255")
    91  	c.Assert(err, gc.ErrorMatches, ".*address matches the same CIDR in multiple spaces")
    92  
    93  	// Check for no-match-found
    94  	_, err = s.spaces.InferSpaceFromAddress("99.99.99.99")
    95  	c.Assert(err, gc.ErrorMatches, ".*unable to infer space for address.*")
    96  }
    97  
    98  func (s *spaceSuite) TestInferSpaceFromCIDRAndSubnetID(c *gc.C) {
    99  	infos := network.SpaceInfos{
   100  		{ID: "1", Name: "space1", Subnets: []network.SubnetInfo{{CIDR: "10.0.0.0/24", ProviderId: "1"}}},
   101  		{ID: "2", Name: "space2", Subnets: []network.SubnetInfo{{CIDR: "10.0.1.0/24", ProviderId: "2"}}},
   102  	}
   103  
   104  	si, err := infos.InferSpaceFromCIDRAndSubnetID("10.0.0.0/24", "1")
   105  	c.Assert(err, jc.ErrorIsNil)
   106  	c.Assert(si.Name, gc.Equals, network.SpaceName("space1"))
   107  
   108  	// Check for same CIDR/different provider
   109  	infos = append(
   110  		infos,
   111  		network.SpaceInfo{
   112  			ID:      "-2",
   113  			Name:    "inverse",
   114  			Subnets: []network.SubnetInfo{{CIDR: "10.0.1.0/24", ProviderId: "3"}},
   115  		},
   116  	)
   117  
   118  	si, err = infos.InferSpaceFromCIDRAndSubnetID("10.0.1.0/24", "2")
   119  	c.Assert(err, jc.ErrorIsNil)
   120  	c.Assert(si.Name, gc.Equals, network.SpaceName("space2"))
   121  
   122  	si, err = infos.InferSpaceFromCIDRAndSubnetID("10.0.1.0/24", "3")
   123  	c.Assert(err, jc.ErrorIsNil)
   124  	c.Assert(si.Name, gc.Equals, network.SpaceName("inverse"))
   125  
   126  	// Check for no-match-found
   127  	_, err = infos.InferSpaceFromCIDRAndSubnetID("10.0.1.0/24", "42")
   128  	c.Assert(err, gc.ErrorMatches, ".*unable to infer space.*")
   129  }
   130  
   131  func (s *spaceSuite) TestAllSubnetInfos(c *gc.C) {
   132  	subnets, err := s.spaces.AllSubnetInfos()
   133  	c.Assert(err, jc.ErrorIsNil)
   134  
   135  	c.Assert(subnets, gc.DeepEquals, network.SubnetInfos{
   136  		{ID: "11", CIDR: "10.0.0.0/24"},
   137  		{ID: "12", CIDR: "10.0.1.0/24"},
   138  		{ID: "13", CIDR: "10.0.2.0/24"},
   139  	})
   140  }
   141  
   142  func (s *spaceSuite) TestFanOverlaysFor(c *gc.C) {
   143  	overlay := network.SubnetInfo{
   144  		ID:   "15",
   145  		CIDR: "10.1.1.0/16",
   146  		FanInfo: &network.FanCIDRs{
   147  			FanLocalUnderlay: "10.0.3.0/24",
   148  			FanOverlay:       "10.1.0.0/8",
   149  		},
   150  	}
   151  
   152  	s.spaces = append(s.spaces, network.SpaceInfo{
   153  		ID:   "4",
   154  		Name: "space4",
   155  		Subnets: network.SubnetInfos{
   156  			{
   157  				ID:   "14",
   158  				CIDR: "10.0.3.0/24",
   159  			},
   160  			overlay,
   161  		},
   162  	})
   163  
   164  	overlays, err := s.spaces.FanOverlaysFor(network.MakeIDSet("11"))
   165  	c.Assert(err, jc.ErrorIsNil)
   166  	c.Assert(overlays, gc.HasLen, 0)
   167  
   168  	overlays, err = s.spaces.FanOverlaysFor(network.MakeIDSet("14"))
   169  	c.Assert(err, jc.ErrorIsNil)
   170  	c.Assert(overlays, gc.DeepEquals, network.SubnetInfos{overlay})
   171  }
   172  
   173  func (s *spaceSuite) TestMoveSubnets(c *gc.C) {
   174  	_, err := s.spaces.MoveSubnets(network.MakeIDSet("11", "12"), "space4")
   175  	c.Check(err, jc.Satisfies, errors.IsNotFound)
   176  
   177  	_, err = s.spaces.MoveSubnets(network.MakeIDSet("666"), "space3")
   178  	c.Check(err, jc.Satisfies, errors.IsNotFound)
   179  
   180  	spaces, err := s.spaces.MoveSubnets(network.MakeIDSet("11", "12"), "space3")
   181  	c.Assert(err, jc.ErrorIsNil)
   182  	c.Assert(spaces, gc.DeepEquals, network.SpaceInfos{
   183  		{ID: "1", Name: "space1", Subnets: nil},
   184  		{ID: "2", Name: "space2", Subnets: nil},
   185  		{
   186  			ID:   "3",
   187  			Name: "space3",
   188  			Subnets: network.SubnetInfos{
   189  				{ID: "13", CIDR: "10.0.2.0/24"},
   190  				{ID: "11", CIDR: "10.0.0.0/24", SpaceID: "3", SpaceName: "space3"},
   191  				{ID: "12", CIDR: "10.0.1.0/24", SpaceID: "3", SpaceName: "space3"},
   192  			},
   193  		},
   194  	})
   195  
   196  	// Ensure the original was not mutated.
   197  	c.Assert(s.spaces, gc.DeepEquals, network.SpaceInfos{
   198  		{ID: "1", Name: "space1", Subnets: []network.SubnetInfo{{ID: "11", CIDR: "10.0.0.0/24"}}},
   199  		{ID: "2", Name: "space2", Subnets: []network.SubnetInfo{{ID: "12", CIDR: "10.0.1.0/24"}}},
   200  		{ID: "3", Name: "space3", Subnets: []network.SubnetInfo{{ID: "13", CIDR: "10.0.2.0/24"}}},
   201  	})
   202  }
   203  
   204  func (s *spaceSuite) TestSubnetCIDRsBySpaceID(c *gc.C) {
   205  	res := s.spaces.SubnetCIDRsBySpaceID()
   206  	c.Assert(res, gc.DeepEquals, map[string][]string{
   207  		"1": {"10.0.0.0/24"},
   208  		"2": {"10.0.1.0/24"},
   209  		"3": {"10.0.2.0/24"},
   210  	})
   211  }
   212  
   213  func (s *spaceSuite) TestConvertSpaceName(c *gc.C) {
   214  	empty := set.Strings{}
   215  	nameTests := []struct {
   216  		name     string
   217  		existing set.Strings
   218  		expected string
   219  	}{
   220  		{"foo", empty, "foo"},
   221  		{"foo1", empty, "foo1"},
   222  		{"Foo Thing", empty, "foo-thing"},
   223  		{"foo^9*//++!!!!", empty, "foo9"},
   224  		{"--Foo", empty, "foo"},
   225  		{"---^^&*()!", empty, "empty"},
   226  		{" ", empty, "empty"},
   227  		{"", empty, "empty"},
   228  		{"foo\u2318", empty, "foo"},
   229  		{"foo--", empty, "foo"},
   230  		{"-foo--foo----bar-", empty, "foo-foo-bar"},
   231  		{"foo-", set.NewStrings("foo", "bar", "baz"), "foo-2"},
   232  		{"foo", set.NewStrings("foo", "foo-2"), "foo-3"},
   233  		{"---", set.NewStrings("empty"), "empty-2"},
   234  	}
   235  	for _, test := range nameTests {
   236  		result := network.ConvertSpaceName(test.name, test.existing)
   237  		c.Check(result, gc.Equals, test.expected)
   238  	}
   239  }