github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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  	globalProviderID := coretesting.ModelTag.Id() + ":" + localProviderID
    60  
    61  	result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{ProviderID: localProviderID})
    62  	c.Assert(result.ProviderID(), gc.Equals, network.Id(localProviderID))
    63  	c.Assert(result.localProviderID(), gc.Equals, localProviderID)
    64  
    65  	result = s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{ProviderID: globalProviderID})
    66  	c.Assert(result.ProviderID(), gc.Equals, network.Id(localProviderID))
    67  	c.Assert(result.localProviderID(), gc.Equals, localProviderID)
    68  }
    69  
    70  func (s *linkLayerDevicesInternalSuite) TestParentDeviceReturnsNoErrorWhenParentNameNotSet(c *gc.C) {
    71  	result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
    72  	parent, err := result.ParentDevice()
    73  	c.Check(parent, gc.IsNil)
    74  	c.Check(err, jc.ErrorIsNil)
    75  }
    76  
    77  func (s *linkLayerDevicesInternalSuite) TestLinkLayerDeviceGlobalKeyHelper(c *gc.C) {
    78  	result := linkLayerDeviceGlobalKey("42", "eno1")
    79  	c.Assert(result, gc.Equals, "m#42#d#eno1")
    80  
    81  	result = linkLayerDeviceGlobalKey("", "")
    82  	c.Assert(result, gc.Equals, "")
    83  }
    84  
    85  func (s *linkLayerDevicesInternalSuite) TestGlobalKeyMethod(c *gc.C) {
    86  	doc := linkLayerDeviceDoc{
    87  		MachineID: "42",
    88  		Name:      "foo",
    89  	}
    90  	config := s.newLinkLayerDeviceWithDummyState(doc)
    91  	c.Check(config.globalKey(), gc.Equals, "m#42#d#foo")
    92  
    93  	config = s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
    94  	c.Check(config.globalKey(), gc.Equals, "")
    95  }
    96  
    97  func (s *linkLayerDevicesInternalSuite) TestParseLinkLayerParentNameAsGlobalKey(c *gc.C) {
    98  	for i, test := range []struct {
    99  		about              string
   100  		input              string
   101  		expectedError      string
   102  		expectedMachineID  string
   103  		expectedParentName string
   104  	}{{
   105  		about: "empty input - empty outputs and no error",
   106  		input: "",
   107  	}, {
   108  		about: "name only as input - empty outputs and no error",
   109  		input: "some-parent",
   110  	}, {
   111  		about:              "global key as input - parsed outputs and no error",
   112  		input:              "m#42#d#br-eth1",
   113  		expectedMachineID:  "42",
   114  		expectedParentName: "br-eth1",
   115  	}, {
   116  		about:         "invalid name as input - empty outputs and NotValidError",
   117  		input:         "some name with not enough # in it",
   118  		expectedError: `ParentName "some name with not enough # in it" format not valid`,
   119  	}, {
   120  		about:         "almost a global key as input - empty outputs and NotValidError",
   121  		input:         "x#foo#y#bar",
   122  		expectedError: `ParentName "x#foo#y#bar" format not valid`,
   123  	}} {
   124  		c.Logf("test #%d: %q", i, test.about)
   125  		gotMachineID, gotParentName, gotError := parseLinkLayerDeviceParentNameAsGlobalKey(test.input)
   126  		if test.expectedError != "" {
   127  			c.Check(gotError, gc.ErrorMatches, test.expectedError)
   128  			c.Check(gotError, jc.Satisfies, errors.IsNotValid)
   129  		} else {
   130  			c.Check(gotError, jc.ErrorIsNil)
   131  		}
   132  		c.Check(gotMachineID, gc.Equals, test.expectedMachineID)
   133  		c.Check(gotParentName, gc.Equals, test.expectedParentName)
   134  	}
   135  }
   136  
   137  func (s *linkLayerDevicesInternalSuite) TestStringIncludesTypeNameAndMachineID(c *gc.C) {
   138  	doc := linkLayerDeviceDoc{
   139  		MachineID: "42",
   140  		Name:      "foo",
   141  		Type:      BondDevice,
   142  	}
   143  	result := s.newLinkLayerDeviceWithDummyState(doc)
   144  	expectedString := `bond device "foo" on machine "42"`
   145  
   146  	c.Assert(result.String(), gc.Equals, expectedString)
   147  }
   148  
   149  func (s *linkLayerDevicesInternalSuite) TestRemainingSimpleGetterMethods(c *gc.C) {
   150  	doc := linkLayerDeviceDoc{
   151  		Name:        "bond0",
   152  		MachineID:   "99",
   153  		MTU:         uint(9000),
   154  		Type:        BondDevice,
   155  		MACAddress:  "aa:bb:cc:dd:ee:f0",
   156  		IsAutoStart: true,
   157  		IsUp:        true,
   158  		ParentName:  "br-bond0",
   159  	}
   160  	result := s.newLinkLayerDeviceWithDummyState(doc)
   161  
   162  	c.Check(result.Name(), gc.Equals, "bond0")
   163  	c.Check(result.MachineID(), gc.Equals, "99")
   164  	c.Check(result.MTU(), gc.Equals, uint(9000))
   165  	c.Check(result.Type(), gc.Equals, BondDevice)
   166  	c.Check(result.MACAddress(), gc.Equals, "aa:bb:cc:dd:ee:f0")
   167  	c.Check(result.IsAutoStart(), jc.IsTrue)
   168  	c.Check(result.IsUp(), jc.IsTrue)
   169  	c.Check(result.ParentName(), gc.Equals, "br-bond0")
   170  }
   171  
   172  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceTypeWithValidValue(c *gc.C) {
   173  	validTypes := []LinkLayerDeviceType{
   174  		LoopbackDevice,
   175  		EthernetDevice,
   176  		VLAN_8021QDevice,
   177  		BondDevice,
   178  		BridgeDevice,
   179  	}
   180  
   181  	for _, value := range validTypes {
   182  		result := IsValidLinkLayerDeviceType(string(value))
   183  		c.Check(result, jc.IsTrue)
   184  	}
   185  }
   186  
   187  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceTypeWithInvalidValue(c *gc.C) {
   188  	result := IsValidLinkLayerDeviceType("")
   189  	c.Check(result, jc.IsFalse)
   190  
   191  	result = IsValidLinkLayerDeviceType("anything")
   192  	c.Check(result, jc.IsFalse)
   193  
   194  	result = IsValidLinkLayerDeviceType(" ")
   195  	c.Check(result, jc.IsFalse)
   196  
   197  	result = IsValidLinkLayerDeviceType("unknown")
   198  	c.Check(result, jc.IsFalse)
   199  }
   200  
   201  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithUnpatchedGOOS(c *gc.C) {
   202  	result := IsValidLinkLayerDeviceName("valid")
   203  	c.Check(result, jc.IsTrue)
   204  }
   205  
   206  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithValidNamesWhenGOOSIsinux(c *gc.C) {
   207  	s.PatchValue(&runtimeGOOS, "linux") // isolate the test from the host machine OS.
   208  
   209  	for i, name := range validUnixDeviceNames {
   210  		c.Logf("test #%d: %q -> valid", i, name)
   211  		result := IsValidLinkLayerDeviceName(name)
   212  		c.Check(result, jc.IsTrue)
   213  	}
   214  }
   215  
   216  var validUnixDeviceNames = []string{
   217  	"eth0", "eno1", "br-eth0.123", "tun:1", "bond0.42",
   218  }
   219  
   220  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithInvalidNamesWhenGOOIsLinux(c *gc.C) {
   221  	s.PatchValue(&runtimeGOOS, "linux") // isolate the test from the host machine OS.
   222  
   223  	result := IsValidLinkLayerDeviceName("")
   224  	c.Check(result, jc.IsFalse)
   225  
   226  	const tooLongLength = 16
   227  	result = IsValidLinkLayerDeviceName(strings.Repeat("x", tooLongLength))
   228  	c.Check(result, jc.IsFalse)
   229  
   230  	result = IsValidLinkLayerDeviceName("with-hash#")
   231  	c.Check(result, jc.IsFalse)
   232  
   233  	result = IsValidLinkLayerDeviceName("has spaces")
   234  	c.Check(result, jc.IsFalse)
   235  
   236  	result = IsValidLinkLayerDeviceName("has\tabs")
   237  	c.Check(result, jc.IsFalse)
   238  
   239  	result = IsValidLinkLayerDeviceName("has\newline")
   240  	c.Check(result, jc.IsFalse)
   241  
   242  	result = IsValidLinkLayerDeviceName("has\r")
   243  	c.Check(result, jc.IsFalse)
   244  
   245  	result = IsValidLinkLayerDeviceName("has\vtab")
   246  	c.Check(result, jc.IsFalse)
   247  
   248  	result = IsValidLinkLayerDeviceName(".")
   249  	c.Check(result, jc.IsFalse)
   250  
   251  	result = IsValidLinkLayerDeviceName("..")
   252  	c.Check(result, jc.IsFalse)
   253  }
   254  
   255  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithValidNamesWhenGOOSNonLinux(c *gc.C) {
   256  	s.PatchValue(&runtimeGOOS, "non-linux") // isolate the test from the host machine OS.
   257  	validDeviceNames := append(validUnixDeviceNames,
   258  		// Windows network device as friendly name and as underlying UUID.
   259  		"Local Area Connection", "{4a62b748-43d0-4136-92e4-22ce7ee31938}",
   260  	)
   261  
   262  	for i, name := range validDeviceNames {
   263  		c.Logf("test #%d: %q -> valid", i, name)
   264  		result := IsValidLinkLayerDeviceName(name)
   265  		c.Check(result, jc.IsTrue)
   266  	}
   267  }
   268  
   269  func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWhenGOOSNonLinux(c *gc.C) {
   270  	s.PatchValue(&runtimeGOOS, "non-linux") // isolate the test from the host machine OS.
   271  
   272  	result := IsValidLinkLayerDeviceName("")
   273  	c.Check(result, jc.IsFalse)
   274  
   275  	const wayTooLongLength = 1024
   276  	result = IsValidLinkLayerDeviceName(strings.Repeat("x", wayTooLongLength))
   277  	c.Check(result, jc.IsFalse)
   278  
   279  	result = IsValidLinkLayerDeviceName("hash# not allowed")
   280  	c.Check(result, jc.IsFalse)
   281  }
   282  
   283  func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenTooShort(c *gc.C) {
   284  	result := stringLengthBetween("", 1, 2)
   285  	c.Check(result, jc.IsFalse)
   286  
   287  	result = stringLengthBetween("", 1, 1)
   288  	c.Check(result, jc.IsFalse)
   289  
   290  	result = stringLengthBetween("1", 2, 3)
   291  	c.Check(result, jc.IsFalse)
   292  
   293  	result = stringLengthBetween("12", 3, 3)
   294  	c.Check(result, jc.IsFalse)
   295  }
   296  
   297  func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenTooLong(c *gc.C) {
   298  	result := stringLengthBetween("1", 0, 0)
   299  	c.Check(result, jc.IsFalse)
   300  
   301  	result = stringLengthBetween("12", 1, 1)
   302  	c.Check(result, jc.IsFalse)
   303  
   304  	result = stringLengthBetween("123", 1, 2)
   305  	c.Check(result, jc.IsFalse)
   306  
   307  	result = stringLengthBetween("123", 0, 1)
   308  	c.Check(result, jc.IsFalse)
   309  }
   310  
   311  func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenWithinLimit(c *gc.C) {
   312  	const (
   313  		minLength = 1
   314  		maxLength = 255
   315  	)
   316  	for i := minLength; i <= maxLength; i++ {
   317  		input := strings.Repeat("x", i)
   318  		result := stringLengthBetween(input, minLength, maxLength)
   319  		c.Check(result, jc.IsTrue)
   320  	}
   321  }