1
// Copyright 2016 Canonical Ltd.
2
// Licensed under the AGPLv3, see LICENCE file for details.
9
"github.com/juju/errors"
10
"github.com/juju/testing"
11
jc "github.com/juju/testing/checkers"
12
gc "gopkg.in/check.v1"
14
"github.com/juju/juju/network"
15
coretesting "github.com/juju/juju/testing"
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
25
var _ = gc.Suite(&linkLayerDevicesInternalSuite{})
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{})
34
func (s *linkLayerDevicesInternalSuite) TestDocIDIncludesModelUUID(c *gc.C) {
35
const localDocID = "foo"
36
globalDocID := coretesting.ModelTag.Id() + ":" + localDocID
38
result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{DocID: localDocID})
39
c.Assert(result.DocID(), gc.Equals, globalDocID)
41
result = s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{DocID: globalDocID})
42
c.Assert(result.DocID(), gc.Equals, globalDocID)
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)
52
func (s *linkLayerDevicesInternalSuite) TestProviderIDIsEmptyWhenNotSet(c *gc.C) {
53
result := s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
54
c.Assert(result.ProviderID(), gc.Equals, network.Id(""))
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))
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)
71
func (s *linkLayerDevicesInternalSuite) TestLinkLayerDeviceGlobalKeyHelper(c *gc.C) {
72
result := linkLayerDeviceGlobalKey("42", "eno1")
73
c.Assert(result, gc.Equals, "m#42#d#eno1")
75
result = linkLayerDeviceGlobalKey("", "")
76
c.Assert(result, gc.Equals, "")
79
func (s *linkLayerDevicesInternalSuite) TestGlobalKeyMethod(c *gc.C) {
80
doc := linkLayerDeviceDoc{
84
config := s.newLinkLayerDeviceWithDummyState(doc)
85
c.Check(config.globalKey(), gc.Equals, "m#42#d#foo")
87
config = s.newLinkLayerDeviceWithDummyState(linkLayerDeviceDoc{})
88
c.Check(config.globalKey(), gc.Equals, "")
91
func (s *linkLayerDevicesInternalSuite) TestParseLinkLayerParentNameAsGlobalKey(c *gc.C) {
92
for i, test := range []struct {
96
expectedMachineID string
97
expectedParentName string
99
about: "empty input - empty outputs and no error",
102
about: "name only as input - empty outputs and no error",
103
input: "some-parent",
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",
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`,
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`,
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)
124
c.Check(gotError, jc.ErrorIsNil)
126
c.Check(gotMachineID, gc.Equals, test.expectedMachineID)
127
c.Check(gotParentName, gc.Equals, test.expectedParentName)
131
func (s *linkLayerDevicesInternalSuite) TestStringIncludesTypeNameAndMachineID(c *gc.C) {
132
doc := linkLayerDeviceDoc{
137
result := s.newLinkLayerDeviceWithDummyState(doc)
138
expectedString := `bond device "foo" on machine "42"`
140
c.Assert(result.String(), gc.Equals, expectedString)
143
func (s *linkLayerDevicesInternalSuite) TestRemainingSimpleGetterMethods(c *gc.C) {
144
doc := linkLayerDeviceDoc{
149
MACAddress: "aa:bb:cc:dd:ee:f0",
152
ParentName: "br-bond0",
154
result := s.newLinkLayerDeviceWithDummyState(doc)
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")
166
func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceTypeWithValidValue(c *gc.C) {
167
validTypes := []LinkLayerDeviceType{
175
for _, value := range validTypes {
176
result := IsValidLinkLayerDeviceType(string(value))
177
c.Check(result, jc.IsTrue)
181
func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceTypeWithInvalidValue(c *gc.C) {
182
result := IsValidLinkLayerDeviceType("")
183
c.Check(result, jc.IsFalse)
185
result = IsValidLinkLayerDeviceType("anything")
186
c.Check(result, jc.IsFalse)
188
result = IsValidLinkLayerDeviceType(" ")
189
c.Check(result, jc.IsFalse)
191
result = IsValidLinkLayerDeviceType("unknown")
192
c.Check(result, jc.IsFalse)
195
func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithUnpatchedGOOS(c *gc.C) {
196
result := IsValidLinkLayerDeviceName("valid")
197
c.Check(result, jc.IsTrue)
200
func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithValidNamesWhenGOOSIsinux(c *gc.C) {
201
s.PatchValue(&runtimeGOOS, "linux") // isolate the test from the host machine OS.
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)
210
var validUnixDeviceNames = []string{
211
"eth0", "eno1", "br-eth0.123", "tun:1", "bond0.42",
214
func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWithInvalidNamesWhenGOOIsLinux(c *gc.C) {
215
s.PatchValue(&runtimeGOOS, "linux") // isolate the test from the host machine OS.
217
result := IsValidLinkLayerDeviceName("")
218
c.Check(result, jc.IsFalse)
220
const tooLongLength = 16
221
result = IsValidLinkLayerDeviceName(strings.Repeat("x", tooLongLength))
222
c.Check(result, jc.IsFalse)
224
result = IsValidLinkLayerDeviceName("with-hash#")
225
c.Check(result, jc.IsFalse)
227
result = IsValidLinkLayerDeviceName("has spaces")
228
c.Check(result, jc.IsFalse)
230
result = IsValidLinkLayerDeviceName("has\tabs")
231
c.Check(result, jc.IsFalse)
233
result = IsValidLinkLayerDeviceName("has\newline")
234
c.Check(result, jc.IsFalse)
236
result = IsValidLinkLayerDeviceName("has\r")
237
c.Check(result, jc.IsFalse)
239
result = IsValidLinkLayerDeviceName("has\vtab")
240
c.Check(result, jc.IsFalse)
242
result = IsValidLinkLayerDeviceName(".")
243
c.Check(result, jc.IsFalse)
245
result = IsValidLinkLayerDeviceName("..")
246
c.Check(result, jc.IsFalse)
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}",
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)
263
func (s *linkLayerDevicesInternalSuite) TestIsValidLinkLayerDeviceNameWhenGOOSNonLinux(c *gc.C) {
264
s.PatchValue(&runtimeGOOS, "non-linux") // isolate the test from the host machine OS.
266
result := IsValidLinkLayerDeviceName("")
267
c.Check(result, jc.IsFalse)
269
const wayTooLongLength = 1024
270
result = IsValidLinkLayerDeviceName(strings.Repeat("x", wayTooLongLength))
271
c.Check(result, jc.IsFalse)
273
result = IsValidLinkLayerDeviceName("hash# not allowed")
274
c.Check(result, jc.IsFalse)
277
func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenTooShort(c *gc.C) {
278
result := stringLengthBetween("", 1, 2)
279
c.Check(result, jc.IsFalse)
281
result = stringLengthBetween("", 1, 1)
282
c.Check(result, jc.IsFalse)
284
result = stringLengthBetween("1", 2, 3)
285
c.Check(result, jc.IsFalse)
287
result = stringLengthBetween("12", 3, 3)
288
c.Check(result, jc.IsFalse)
291
func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenTooLong(c *gc.C) {
292
result := stringLengthBetween("1", 0, 0)
293
c.Check(result, jc.IsFalse)
295
result = stringLengthBetween("12", 1, 1)
296
c.Check(result, jc.IsFalse)
298
result = stringLengthBetween("123", 1, 2)
299
c.Check(result, jc.IsFalse)
301
result = stringLengthBetween("123", 0, 1)
302
c.Check(result, jc.IsFalse)
305
func (s *linkLayerDevicesInternalSuite) TestStringLengthBetweenWhenWithinLimit(c *gc.C) {
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)