github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/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 }