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 }