github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/state/linklayerdevices_internal_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package state
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/testing"
    11  	jc "github.com/juju/testing/checkers"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/network"
    15  	coretesting "github.com/juju/juju/testing"
    16  )
    17  
    18  // linkLayerDevicesInternalSuite contains black-box tests for link-layer network
    19  // devices' internals, which do not actually access mongo. The rest of the logic
    20  // is tested in linkLayerDevicesStateSuite.
    21  type linkLayerDevicesInternalSuite struct {
    22  	testing.IsolationSuite
    23  }
    24  
    25  var _ = gc.Suite(&linkLayerDevicesInternalSuite{})
    26  
    27  func (s *linkLayerDevicesInternalSuite) TestNewLinkLayerDeviceCreatesLinkLayerDevice(c *gc.C) {
    28  	result := newLinkLayerDevice(nil, linkLayerDeviceDoc{})
    29  	c.Assert(result, gc.NotNil)
    30  	c.Assert(result.st, gc.IsNil)
    31  	c.Assert(result.doc, jc.DeepEquals, linkLayerDeviceDoc{})
    32  }
    33  
    34  func (s *linkLayerDevicesInternalSuite) TestDocIDIncludesModelUUID(c *gc.C) {
    35  	const localDocID = "foo"
    36  	globalDocID := coretesting.ModelTag.Id() + ":" + localDocID
    37  
    38  	result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{DocID: localDocID})
    39  	c.Assert(result.DocID(), gc.Equals, globalDocID)
    40  
    41  	result = s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{DocID: globalDocID})
    42  	c.Assert(result.DocID(), gc.Equals, globalDocID)
    43  }
    44  
    45  func (s *linkLayerDevicesInternalSuite) newLinkLayerDeviceWithDummyState(doc linkLayerDeviceDoc) *LinkLayerDevice {
    46  	// We only need the model UUID set for localID() and docID() to work.
    47  	// The rest is tested in linkLayerDevicesStateSuite.
    48  	dummyState := &State{modelTag: coretesting.ModelTag}
    49  	return newLinkLayerDevice(dummyState, doc)
    50  }
    51  
    52  func (s *linkLayerDevicesInternalSuite) TestProviderIDIsEmptyWhenNotSet(c *gc.C) {
    53  	result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
    54  	c.Assert(result.ProviderID(), gc.Equals, network.Id(""))
    55  }
    56  
    57  func (s *linkLayerDevicesInternalSuite) TestProviderIDDoesNotIncludeModelUUIDWhenSet(c *gc.C) {
    58  	const localProviderID = "foo"
    59  	result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{ProviderID: localProviderID})
    60  	c.Assert(result.ProviderID(), gc.Equals, network.Id(localProviderID))
    61  
    62  }
    63  
    64  func (s *linkLayerDevicesInternalSuite) TestParentDeviceReturnsNoErrorWhenParentNameNotSet(c *gc.C) {
    65  	result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
    66  	parent, err := result.ParentDevice()
    67  	c.Check(parent, gc.IsNil)
    68  	c.Check(err, jc.ErrorIsNil)
    69  }
    70  
    71  func (s *linkLayerDevicesInternalSuite) TestLinkLayerDeviceGlobalKeyHelper(c *gc.C) {
    72  	result := linkLayerDeviceGlobalKey("42", "eno1")
    73  	c.Assert(result, gc.Equals, "m#42#d#eno1")
    74  
    75  	result = linkLayerDeviceGlobalKey("", "")
    76  	c.Assert(result, gc.Equals, "")
    77  }
    78  
    79  func (s *linkLayerDevicesInternalSuite) TestGlobalKeyMethod(c *gc.C) {
    80  	doc := linkLayerDeviceDoc{
    81  		MachineID: "42",
    82  		Name:      "foo",
    83  	}
    84  	config := s.newLinkLayerDeviceWithDummyState(doc)
    85  	c.Check(config.globalKey(), gc.Equals, "m#42#d#foo")
    86  
    87  	config = s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
    88  	c.Check(config.globalKey(), gc.Equals, "")
    89  }
    90  
    91  func (s *linkLayerDevicesInternalSuite) TestParseLinkLayerParentNameAsGlobalKey(c *gc.C) {
    92  	for i, test := range []struct {
    93  		about              string
    94  		input              string
    95  		expectedError      string
    96  		expectedMachineID  string
    97  		expectedParentName string
    98  	}{{
    99  		about: "empty input - empty outputs and no error",
   100  		input: "",
   101  	}, {
   102  		about: "name only as input - empty outputs and no error",
   103  		input: "some-parent",
   104  	}, {
   105  		about:              "global key as input - parsed outputs and no error",
   106  		input:              "m#42#d#br-eth1",
   107  		expectedMachineID:  "42",
   108  		expectedParentName: "br-eth1",
   109  	}, {
   110  		about:         "invalid name as input - empty outputs and NotValidError",
   111  		input:         "some name with not enough # in it",
   112  		expectedError: `ParentName "some name with not enough # in it" format not valid`,
   113  	}, {
   114  		about:         "almost a global key as input - empty outputs and NotValidError",
   115  		input:         "x#foo#y#bar",
   116  		expectedError: `ParentName "x#foo#y#bar" format not valid`,
   117  	}} {
   118  		c.Logf("test #%d: %q", i, test.about)
   119  		gotMachineID, gotParentName, gotError := parseLinkLayerDeviceParentNameAsGlobalKey(test.input)
   120  		if test.expectedError != "" {
   121  			c.Check(gotError, gc.ErrorMatches, test.expectedError)
   122  			c.Check(gotError, jc.Satisfies, errors.IsNotValid)
   123  		} else {
   124  			c.Check(gotError, jc.ErrorIsNil)
   125  		}
   126  		c.Check(gotMachineID, gc.Equals, test.expectedMachineID)
   127  		c.Check(gotParentName, gc.Equals, test.expectedParentName)
   128  	}
   129  }
   130  
   131  func (s *linkLayerDevicesInternalSuite) TestStringIncludesTypeNameAndMachineID(c *gc.C) {
   132  	doc := linkLayerDeviceDoc{
   133  		MachineID: "42",
   134  		Name:      "foo",
   135  		Type:      BondDevice,
   136  	}
   137  	result := s.newLinkLayerDeviceWithDummyState(doc)
   138  	expectedString := `bond device "foo" on machine "42"`
   139  
   140  	c.Assert(result.String(), gc.Equals, expectedString)
   141  }
   142  
   143  func (s *linkLayerDevicesInternalSuite) TestRemainingSimpleGetterMethods(c *gc.C) {
   144  	doc := linkLayerDeviceDoc{
   145  		Name:        "bond0",
   146  		MachineID:   "99",
   147  		MTU:         uint(9000),
   148  		Type:        BondDevice,
   149  		MACAddress:  "aa:bb:cc:dd:ee:f0",
   150  		IsAutoStart: true,
   151  		IsUp:        true,
   152  		ParentName:  "br-bond0",
   153  	}
   154  	result := s.newLinkLayerDeviceWithDummyState(doc)
   155  
   156  	c.Check(result.Name(), gc.Equals, "bond0")
   157  	c.Check(result.MachineID(), gc.Equals, "99")
   158  	c.Check(result.MTU(), gc.Equals, uint(9000))
   159  	c.Check(result.Type(), gc.Equals, BondDevice)
   160  	c.Check(result.MACAddress(), gc.Equals, "aa:bb:cc:dd:ee:f0")
   161  	c.Check(result.IsAutoStart(), jc.IsTrue)
   162  	c.Check(result.IsUp(), jc.IsTrue)
   163  	c.Check(result.ParentName(), gc.Equals, "br-bond0")
   164  }
   165  
   166  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceTypeWithValidValue(c *gc.C) {
   167  	validTypes := []LinkLayerDeviceType{
   168  		LoopbackDevice,
   169  		EthernetDevice,
   170  		VLAN_8021QDevice,
   171  		BondDevice,
   172  		BridgeDevice,
   173  	}
   174  
   175  	for _, value := range validTypes {
   176  		result := IsValidLinkLayerDeviceType(string(value))
   177  		c.Check(result, jc.IsTrue)
   178  	}
   179  }
   180  
   181  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceTypeWithInvalidValue(c *gc.C) {
   182  	result := IsValidLinkLayerDeviceType("")
   183  	c.Check(result, jc.IsFalse)
   184  
   185  	result = IsValidLinkLayerDeviceType("anything")
   186  	c.Check(result, jc.IsFalse)
   187  
   188  	result = IsValidLinkLayerDeviceType(" ")
   189  	c.Check(result, jc.IsFalse)
   190  
   191  	result = IsValidLinkLayerDeviceType("unknown")
   192  	c.Check(result, jc.IsFalse)
   193  }
   194  
   195  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithUnpatchedGOOS(c *gc.C) {
   196  	result := IsValidLinkLayerDeviceName("valid")
   197  	c.Check(result, jc.IsTrue)
   198  }
   199  
   200  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithValidNamesWhenGOOSIsinux(c *gc.C) {
   201  	s.PatchValue(&runtimeGOOS, "linux") // isolate the test from the host machine OS.
   202  
   203  	for i, name := range validUnixDeviceNames {
   204  		c.Logf("test #%d: %q -> valid", i, name)
   205  		result := IsValidLinkLayerDeviceName(name)
   206  		c.Check(result, jc.IsTrue)
   207  	}
   208  }
   209  
   210  var validUnixDeviceNames = []string{
   211  	"eth0", "eno1", "br-eth0.123", "tun:1", "bond0.42",
   212  }
   213  
   214  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithInvalidNamesWhenGOOIsLinux(c *gc.C) {
   215  	s.PatchValue(&runtimeGOOS, "linux") // isolate the test from the host machine OS.
   216  
   217  	result := IsValidLinkLayerDeviceName("")
   218  	c.Check(result, jc.IsFalse)
   219  
   220  	const tooLongLength = 16
   221  	result = IsValidLinkLayerDeviceName(strings.Repeat("x", tooLongLength))
   222  	c.Check(result, jc.IsFalse)
   223  
   224  	result = IsValidLinkLayerDeviceName("with-hash#")
   225  	c.Check(result, jc.IsFalse)
   226  
   227  	result = IsValidLinkLayerDeviceName("has spaces")
   228  	c.Check(result, jc.IsFalse)
   229  
   230  	result = IsValidLinkLayerDeviceName("has\tabs")
   231  	c.Check(result, jc.IsFalse)
   232  
   233  	result = IsValidLinkLayerDeviceName("has\newline")
   234  	c.Check(result, jc.IsFalse)
   235  
   236  	result = IsValidLinkLayerDeviceName("has\r")
   237  	c.Check(result, jc.IsFalse)
   238  
   239  	result = IsValidLinkLayerDeviceName("has\vtab")
   240  	c.Check(result, jc.IsFalse)
   241  
   242  	result = IsValidLinkLayerDeviceName(".")
   243  	c.Check(result, jc.IsFalse)
   244  
   245  	result = IsValidLinkLayerDeviceName("..")
   246  	c.Check(result, jc.IsFalse)
   247  }
   248  
   249  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithValidNamesWhenGOOSNonLinux(c *gc.C) {
   250  	s.PatchValue(&runtimeGOOS, "non-linux") // isolate the test from the host machine OS.
   251  	validDeviceNames := append(validUnixDeviceNames,
   252  		// Windows network device as friendly name and as underlying UUID.
   253  		"Local Area Connection", "{4a62b748-43d0-4136-92e4-22ce7ee31938}",
   254  	)
   255  
   256  	for i, name := range validDeviceNames {
   257  		c.Logf("test #%d: %q -> valid", i, name)
   258  		result := IsValidLinkLayerDeviceName(name)
   259  		c.Check(result, jc.IsTrue)
   260  	}
   261  }
   262  
   263  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWhenGOOSNonLinux(c *gc.C) {
   264  	s.PatchValue(&runtimeGOOS, "non-linux") // isolate the test from the host machine OS.
   265  
   266  	result := IsValidLinkLayerDeviceName("")
   267  	c.Check(result, jc.IsFalse)
   268  
   269  	const wayTooLongLength = 1024
   270  	result = IsValidLinkLayerDeviceName(strings.Repeat("x", wayTooLongLength))
   271  	c.Check(result, jc.IsFalse)
   272  
   273  	result = IsValidLinkLayerDeviceName("hash# not allowed")
   274  	c.Check(result, jc.IsFalse)
   275  }
   276  
   277  func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenTooShort(c *gc.C) {
   278  	result := stringLengthBetween("", 1, 2)
   279  	c.Check(result, jc.IsFalse)
   280  
   281  	result = stringLengthBetween("", 1, 1)
   282  	c.Check(result, jc.IsFalse)
   283  
   284  	result = stringLengthBetween("1", 2, 3)
   285  	c.Check(result, jc.IsFalse)
   286  
   287  	result = stringLengthBetween("12", 3, 3)
   288  	c.Check(result, jc.IsFalse)
   289  }
   290  
   291  func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenTooLong(c *gc.C) {
   292  	result := stringLengthBetween("1", 0, 0)
   293  	c.Check(result, jc.IsFalse)
   294  
   295  	result = stringLengthBetween("12", 1, 1)
   296  	c.Check(result, jc.IsFalse)
   297  
   298  	result = stringLengthBetween("123", 1, 2)
   299  	c.Check(result, jc.IsFalse)
   300  
   301  	result = stringLengthBetween("123", 0, 1)
   302  	c.Check(result, jc.IsFalse)
   303  }
   304  
   305  func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenWithinLimit(c *gc.C) {
   306  	const (
   307  		minLength = 1
   308  		maxLength = 255
   309  	)
   310  	for i := minLength; i <= maxLength; i++ {
   311  		input := strings.Repeat("x", i)
   312  		result := stringLengthBetween(input, minLength, maxLength)
   313  		c.Check(result, jc.IsTrue)
   314  	}
   315  }