github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/network/debinterfaces/parser_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package debinterfaces_test 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 11 "github.com/juju/testing" 12 jc "github.com/juju/testing/checkers" 13 gc "gopkg.in/check.v1" 14 15 "github.com/juju/juju/network/debinterfaces" 16 ) 17 18 type ParserSuite struct { 19 testing.IsolationSuite 20 21 expander debinterfaces.WordExpander 22 } 23 24 var _ = gc.Suite(&ParserSuite{}) 25 26 // Ensure wordExpanderWithError is a WordExpander 27 var _ debinterfaces.WordExpander = (*wordExpanderErrors)(nil) 28 29 type wordExpanderErrors struct { 30 errmsg string 31 } 32 33 func wordExpanderWithError(errmsg string) debinterfaces.WordExpander { 34 return &wordExpanderErrors{errmsg: errmsg} 35 } 36 37 func (w *wordExpanderErrors) Expand(s string) ([]string, error) { 38 return nil, fmt.Errorf("word expansion failed: %s", w.errmsg) 39 } 40 41 func (s *ParserSuite) SetUpTest(c *gc.C) { 42 s.expander = debinterfaces.NewWordExpander() 43 } 44 45 func (s *ParserSuite) TestNilInput(c *gc.C) { 46 interfaces, err := debinterfaces.ParseSource("", nil, s.expander) 47 c.Assert(interfaces, gc.IsNil) 48 c.Check(err, gc.ErrorMatches, "filename and input is nil") 49 } 50 51 func (s *ParserSuite) TestNilInputAndNoFilename(c *gc.C) { 52 stanzas, err := debinterfaces.ParseSource("", "", s.expander) 53 c.Assert(err, gc.IsNil) 54 c.Check(stanzas, gc.HasLen, 0) 55 } 56 57 func (s *ParserSuite) TestUnsupportedInputType(c *gc.C) { 58 stanzas, err := debinterfaces.ParseSource("", []float64{3.141}, s.expander) 59 c.Assert(err, gc.ErrorMatches, "invalid source type") 60 c.Check(stanzas, gc.IsNil) 61 } 62 63 func (s *ParserSuite) TestFilenameEmpty(c *gc.C) { 64 emptyFile := filepath.Join(c.MkDir(), "TestFilenameEmpty") 65 err := os.WriteFile(emptyFile, []byte(""), 0644) 66 c.Assert(err, gc.IsNil) 67 stanzas, err := debinterfaces.ParseSource(emptyFile, nil, s.expander) 68 c.Assert(err, gc.IsNil) 69 c.Check(stanzas, gc.HasLen, 0) 70 } 71 72 func (s *ParserSuite) TestParseErrorObject(c *gc.C) { 73 content := `hunky dory` 74 _, err := debinterfaces.ParseSource("", content, s.expander) 75 c.Assert(err, gc.NotNil) 76 _, parseError := err.(*debinterfaces.ParseError) 77 c.Assert(parseError, gc.NotNil) 78 c.Assert(err, gc.ErrorMatches, "misplaced option") 79 } 80 81 func (s *ParserSuite) TestCommentsAndBlankLinesOnly(c *gc.C) { 82 content := ` 83 84 # Comment 1. 85 86 # Comment 2, after empty line. 87 88 # An indented comment, followed by a line with leading whitespace 89 90 ` 91 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 92 c.Assert(err, gc.IsNil) 93 c.Assert(stanzas, gc.HasLen, 0) 94 } 95 96 func (s *ParserSuite) TestAllowStanzaMissingArg(c *gc.C) { 97 _, err := debinterfaces.ParseSource("", "allow-hotplug", s.expander) 98 c.Assert(err, gc.NotNil) 99 c.Check(err, gc.ErrorMatches, "missing device name") 100 } 101 102 func (s *ParserSuite) TestAutoStanzaMissingArg(c *gc.C) { 103 _, err := debinterfaces.ParseSource("", "auto", s.expander) 104 c.Assert(err, gc.NotNil) 105 c.Check(err, gc.ErrorMatches, "missing device name") 106 } 107 108 func (s *ParserSuite) TestIfaceStanzaMissingArg(c *gc.C) { 109 _, err := debinterfaces.ParseSource("", "iface", s.expander) 110 c.Assert(err, gc.NotNil) 111 c.Check(err, gc.ErrorMatches, "missing device name") 112 } 113 114 func (s *ParserSuite) TestMappingStanzaMissingArg(c *gc.C) { 115 _, err := debinterfaces.ParseSource("", "mapping", s.expander) 116 c.Assert(err, gc.NotNil) 117 c.Check(err, gc.ErrorMatches, "missing device name") 118 } 119 120 func (s *ParserSuite) TestNoAutoDownStanzaMissingArg(c *gc.C) { 121 _, err := debinterfaces.ParseSource("", "no-auto-down", s.expander) 122 c.Assert(err, gc.NotNil) 123 c.Check(err, gc.ErrorMatches, "missing device name") 124 } 125 126 func (s *ParserSuite) TestNoScriptsStanzaMissingArg(c *gc.C) { 127 _, err := debinterfaces.ParseSource("", "no-scripts", s.expander) 128 c.Assert(err, gc.NotNil) 129 c.Check(err, gc.ErrorMatches, "missing device name") 130 } 131 132 func (s *ParserSuite) TestSourceStanzaMissingArg(c *gc.C) { 133 _, err := debinterfaces.ParseSource("", "source", s.expander) 134 c.Assert(err, gc.NotNil) 135 c.Check(err, gc.ErrorMatches, "missing filename") 136 } 137 138 func (s *ParserSuite) TestSourceDirectoryStanzaMissingArg(c *gc.C) { 139 _, err := debinterfaces.ParseSource("", "source-directory", s.expander) 140 c.Assert(err, gc.NotNil) 141 c.Check(err, gc.ErrorMatches, "missing directory") 142 } 143 144 func (s *ParserSuite) TestAllowStanza(c *gc.C) { 145 definition := "allow-hotplug eth0 eth1 eth2" 146 stanzas, err := debinterfaces.ParseSource("", definition, s.expander) 147 c.Assert(err, gc.IsNil) 148 c.Assert(stanzas, gc.HasLen, 1) 149 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.AllowStanza{}) 150 allow := stanzas[0].(debinterfaces.AllowStanza) 151 c.Check(allow.Location().Filename, gc.Equals, "") 152 c.Check(allow.Location().LineNum, gc.Equals, 1) 153 c.Assert(allow.Definition(), gc.HasLen, 1) 154 c.Check(allow.Definition()[0], gc.Equals, definition) 155 c.Check(allow.DeviceNames, gc.DeepEquals, []string{"eth0", "eth1", "eth2"}) 156 } 157 158 func (s *ParserSuite) TestAutoStanza(c *gc.C) { 159 definition := "auto eth0 eth1 eth2" 160 stanzas, err := debinterfaces.ParseSource("", definition, s.expander) 161 c.Assert(err, gc.IsNil) 162 c.Assert(stanzas, gc.HasLen, 1) 163 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 164 auto := stanzas[0].(debinterfaces.AutoStanza) 165 c.Check(auto.Location().Filename, gc.Equals, "") 166 c.Check(auto.Location().LineNum, gc.Equals, 1) 167 c.Assert(auto.Definition(), gc.HasLen, 1) 168 c.Check(auto.Definition()[0], gc.Equals, definition) 169 c.Check(auto.DeviceNames, gc.DeepEquals, []string{"eth0", "eth1", "eth2"}) 170 } 171 172 func (s *ParserSuite) TestWithIfaceStanzaAndOneOption(c *gc.C) { 173 content := ` 174 iface eth0 inet manual 175 # A comment. 176 address 192.168.1.254/24 ` 177 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 178 c.Assert(err, gc.IsNil) 179 c.Assert(stanzas, gc.HasLen, 1) 180 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 181 iface := stanzas[0].(debinterfaces.IfaceStanza) 182 c.Assert(iface.Definition(), gc.HasLen, 2) 183 c.Check(iface.Definition()[0], gc.Equals, "iface eth0 inet manual") 184 c.Check(iface.Definition()[1], gc.Equals, "address 192.168.1.254/24") 185 c.Check(iface.Location().Filename, gc.Equals, "") 186 c.Check(iface.Location().LineNum, gc.Equals, 2) 187 c.Check(iface.Options, gc.HasLen, 1) 188 c.Check(iface.Options[0], gc.Equals, "address 192.168.1.254/24") 189 c.Check(iface.HasBondMasterOption, gc.Equals, false) 190 c.Check(iface.HasBondOptions, gc.Equals, false) 191 c.Check(iface.IsAlias, gc.Equals, false) 192 c.Check(iface.IsBridged, gc.Equals, false) 193 c.Check(iface.IsVLAN, gc.Equals, false) 194 } 195 196 func (s *ParserSuite) TestWithIfaceStanzaAndMultipleOptions(c *gc.C) { 197 content := ` 198 iface eth0 inet manual 199 # A comment. 200 address 192.168.1.254/24 201 dns-nameservers 8.8.8.8 202 # Another comment. 203 dns-search ubuntu.com 204 # An ending comment` 205 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 206 c.Assert(err, gc.IsNil) 207 c.Assert(stanzas, gc.HasLen, 1) 208 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 209 iface := stanzas[0].(debinterfaces.IfaceStanza) 210 c.Assert(iface.Definition(), gc.HasLen, 4) 211 c.Check(iface.Definition()[0], gc.Equals, "iface eth0 inet manual") 212 c.Check(iface.Definition()[1], gc.Equals, "address 192.168.1.254/24") 213 c.Check(iface.Definition()[2], gc.Equals, "dns-nameservers 8.8.8.8") 214 c.Check(iface.Definition()[3], gc.Equals, "dns-search ubuntu.com") 215 c.Check(iface.Location().Filename, gc.Equals, "") 216 c.Check(iface.Location().LineNum, gc.Equals, 2) 217 c.Assert(iface.Options, gc.HasLen, 3) 218 c.Check(iface.Options[0], gc.Equals, "address 192.168.1.254/24") 219 c.Check(iface.Options[1], gc.Equals, "dns-nameservers 8.8.8.8") 220 c.Check(iface.Options[2], gc.Equals, "dns-search ubuntu.com") 221 c.Check(iface.HasBondMasterOption, gc.Equals, false) 222 c.Check(iface.HasBondOptions, gc.Equals, false) 223 c.Check(iface.IsAlias, gc.Equals, false) 224 c.Check(iface.IsBridged, gc.Equals, false) 225 c.Check(iface.IsVLAN, gc.Equals, false) 226 } 227 228 func (s *ParserSuite) TestWithIfaceStanzaAndNoOptions(c *gc.C) { 229 content := ` 230 iface eth0 inet manual 231 # A comment.` 232 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 233 c.Assert(err, gc.IsNil) 234 c.Assert(stanzas, gc.HasLen, 1) 235 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 236 iface := stanzas[0].(debinterfaces.IfaceStanza) 237 c.Assert(iface.Definition(), gc.HasLen, 1) 238 c.Check(iface.Definition()[0], gc.Equals, "iface eth0 inet manual") 239 c.Check(iface.Location().Filename, gc.Equals, "") 240 c.Check(iface.Location().LineNum, gc.Equals, 2) 241 c.Check(iface.Options, gc.HasLen, 0) 242 c.Check(iface.HasBondMasterOption, gc.Equals, false) 243 c.Check(iface.HasBondOptions, gc.Equals, false) 244 c.Check(iface.IsAlias, gc.Equals, false) 245 c.Check(iface.IsBridged, gc.Equals, false) 246 c.Check(iface.IsVLAN, gc.Equals, false) 247 } 248 249 func (s *ParserSuite) TestAutoStanzaFollowedByIfaceStanza(c *gc.C) { 250 content := ` 251 auto eth0 252 253 iface eth0 inet static 254 address 192.168.1.254/24 255 gateway 192.168.1.1` 256 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 257 c.Assert(err, gc.IsNil) 258 c.Assert(stanzas, gc.HasLen, 2) 259 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 260 c.Assert(stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 261 262 auto := stanzas[0].(debinterfaces.AutoStanza) 263 c.Assert(auto.Definition(), gc.HasLen, 1) 264 c.Check(auto.Definition()[0], gc.Equals, "auto eth0") 265 c.Check(auto.Location().Filename, gc.Equals, "") 266 c.Check(auto.Location().LineNum, gc.Equals, 2) 267 268 iface := stanzas[1].(debinterfaces.IfaceStanza) 269 c.Assert(iface.Definition(), gc.HasLen, 3) 270 c.Check(iface.Definition()[0], gc.Equals, "iface eth0 inet static") 271 c.Check(iface.Definition()[1], gc.Equals, "address 192.168.1.254/24") 272 c.Check(iface.Definition()[2], gc.Equals, "gateway 192.168.1.1") 273 c.Check(iface.Location().Filename, gc.Equals, "") 274 c.Check(iface.Location().LineNum, gc.Equals, 4) 275 c.Assert(iface.Options, gc.HasLen, 2) 276 c.Check(iface.Options[0], gc.Equals, "address 192.168.1.254/24") 277 c.Check(iface.Options[1], gc.Equals, "gateway 192.168.1.1") 278 c.Check(iface.HasBondMasterOption, gc.Equals, false) 279 c.Check(iface.HasBondOptions, gc.Equals, false) 280 c.Check(iface.IsAlias, gc.Equals, false) 281 c.Check(iface.IsBridged, gc.Equals, false) 282 c.Check(iface.IsVLAN, gc.Equals, false) 283 } 284 285 func (s *ParserSuite) TestVLANIfaceStanza(c *gc.C) { 286 content := ` 287 iface eth0.100 inet static 288 address 192.168.1.254/24 289 vlan-raw-device eth1` 290 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 291 c.Assert(err, gc.IsNil) 292 c.Assert(stanzas, gc.HasLen, 1) 293 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 294 295 iface := stanzas[0].(debinterfaces.IfaceStanza) 296 c.Assert(iface.Definition(), gc.HasLen, 3) 297 c.Check(iface.Definition()[0], gc.Equals, "iface eth0.100 inet static") 298 c.Check(iface.Definition()[1], gc.Equals, "address 192.168.1.254/24") 299 c.Check(iface.Definition()[2], gc.Equals, "vlan-raw-device eth1") 300 c.Check(iface.Location().Filename, gc.Equals, "") 301 c.Check(iface.Location().LineNum, gc.Equals, 2) 302 c.Assert(iface.Options, gc.HasLen, 2) 303 c.Check(iface.Options[0], gc.Equals, "address 192.168.1.254/24") 304 c.Check(iface.Options[1], gc.Equals, "vlan-raw-device eth1") 305 c.Check(iface.HasBondMasterOption, gc.Equals, false) 306 c.Check(iface.HasBondOptions, gc.Equals, false) 307 c.Check(iface.IsAlias, gc.Equals, false) 308 c.Check(iface.IsBridged, gc.Equals, false) 309 c.Check(iface.IsVLAN, gc.Equals, true) 310 } 311 312 func (s *ParserSuite) TestBondedIfaceStanza(c *gc.C) { 313 content := ` 314 auto eth0 315 iface eth0 inet manual 316 bond-lacp_rate slow 317 bond-xmit_hash_policy layer2 318 bond-miimon 100 319 bond-master bond0 320 bond-mode active-backup 321 322 auto eth1 323 iface eth1 inet manual 324 bond-lacp_rate slow 325 bond-xmit_hash_policy layer2 326 bond-miimon 100 327 bond-master bond0 328 mtu 1500 329 bond-mode active-backup 330 331 auto bond0 332 iface bond0 inet dhcp 333 bond-lacp_rate slow 334 bond-xmit_hash_policy layer2 335 bond-miimon 100 336 mtu 1500 337 bond-mode active-backup 338 hwaddress 52:54:00:1c:f1:5b 339 bond-slaves none` 340 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 341 c.Assert(err, gc.IsNil) 342 c.Assert(stanzas, gc.HasLen, 6) 343 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 344 c.Assert(stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 345 c.Assert(stanzas[2], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 346 c.Assert(stanzas[3], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 347 c.Assert(stanzas[4], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 348 c.Assert(stanzas[5], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 349 350 iface0 := stanzas[1].(debinterfaces.IfaceStanza) 351 c.Assert(iface0.Definition(), gc.HasLen, 6) 352 c.Check(iface0.Definition()[0], gc.Equals, "iface eth0 inet manual") 353 c.Check(iface0.Location().Filename, gc.Equals, "") 354 c.Check(iface0.Location().LineNum, gc.Equals, 3) 355 c.Check(iface0.Options, gc.HasLen, 5) 356 c.Check(iface0.HasBondMasterOption, gc.Equals, true) 357 c.Check(iface0.HasBondOptions, gc.Equals, true) 358 c.Check(iface0.IsAlias, gc.Equals, false) 359 c.Check(iface0.IsBridged, gc.Equals, false) 360 c.Check(iface0.IsVLAN, gc.Equals, false) 361 362 iface1 := stanzas[3].(debinterfaces.IfaceStanza) 363 c.Assert(iface1.Definition(), gc.HasLen, 7) 364 c.Check(iface1.Definition()[0], gc.Equals, "iface eth1 inet manual") 365 c.Check(iface1.Location().Filename, gc.Equals, "") 366 c.Check(iface1.Location().LineNum, gc.Equals, 11) 367 c.Check(iface1.Options, gc.HasLen, 6) 368 c.Check(iface1.HasBondMasterOption, gc.Equals, true) 369 c.Check(iface1.HasBondOptions, gc.Equals, true) 370 c.Check(iface1.IsAlias, gc.Equals, false) 371 c.Check(iface1.IsBridged, gc.Equals, false) 372 c.Check(iface1.IsVLAN, gc.Equals, false) 373 374 iface2 := stanzas[5].(debinterfaces.IfaceStanza) 375 c.Assert(iface2.Definition(), gc.HasLen, 8) 376 c.Check(iface2.Definition()[0], gc.Equals, "iface bond0 inet dhcp") 377 c.Check(iface2.Location().Filename, gc.Equals, "") 378 c.Check(iface2.Location().LineNum, gc.Equals, 20) 379 c.Check(iface2.Options, gc.HasLen, 7) 380 c.Check(iface2.HasBondOptions, gc.Equals, true) 381 c.Check(iface2.HasBondMasterOption, gc.Equals, false) 382 c.Check(iface2.IsAlias, gc.Equals, false) 383 c.Check(iface2.IsBridged, gc.Equals, false) 384 c.Check(iface2.IsVLAN, gc.Equals, false) 385 } 386 387 func (s *ParserSuite) TestMappingStanza(c *gc.C) { 388 content := ` 389 mapping eth0 eth1 390 script /path/to/get-mac-address.sh 391 map 11:22:33:44:55:66 lan 392 map AA:BB:CC:DD:EE:FF internet` 393 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 394 c.Assert(err, gc.IsNil) 395 c.Assert(stanzas, gc.HasLen, 1) 396 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.MappingStanza{}) 397 398 mapping := stanzas[0].(debinterfaces.MappingStanza) 399 c.Assert(mapping.Definition(), gc.HasLen, 4) 400 c.Check(mapping.Definition()[0], gc.Equals, "mapping eth0 eth1") 401 c.Check(mapping.Location().Filename, gc.Equals, "") 402 c.Check(mapping.Location().LineNum, gc.Equals, 2) 403 c.Check(mapping.DeviceNames, gc.DeepEquals, []string{"eth0", "eth1"}) 404 c.Assert(mapping.Options, gc.HasLen, 3) 405 c.Check(mapping.Options[0], gc.Equals, "script /path/to/get-mac-address.sh") 406 c.Check(mapping.Options[1], gc.Equals, "map 11:22:33:44:55:66 lan") 407 c.Check(mapping.Options[2], gc.Equals, "map AA:BB:CC:DD:EE:FF internet") 408 } 409 410 func (s *ParserSuite) TestNoAutoDownStanza(c *gc.C) { 411 content := `no-auto-down eth0 eth1` 412 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 413 c.Assert(err, gc.IsNil) 414 c.Assert(stanzas, gc.HasLen, 1) 415 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.NoAutoDownStanza{}) 416 417 noautodown := stanzas[0].(debinterfaces.NoAutoDownStanza) 418 c.Assert(noautodown.Definition(), gc.HasLen, 1) 419 c.Check(noautodown.Definition()[0], gc.Equals, "no-auto-down eth0 eth1") 420 c.Check(noautodown.Location().Filename, gc.Equals, "") 421 c.Check(noautodown.Location().LineNum, gc.Equals, 1) 422 c.Check(noautodown.DeviceNames, gc.DeepEquals, []string{"eth0", "eth1"}) 423 } 424 425 func (s *ParserSuite) TestNoScriptsStanza(c *gc.C) { 426 content := `no-scripts eth0 eth1` 427 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 428 c.Assert(err, gc.IsNil) 429 c.Assert(stanzas, gc.HasLen, 1) 430 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.NoScriptsStanza{}) 431 432 noscripts := stanzas[0].(debinterfaces.NoScriptsStanza) 433 c.Assert(noscripts.Definition(), gc.HasLen, 1) 434 c.Check(noscripts.Definition()[0], gc.Equals, "no-scripts eth0 eth1") 435 c.Check(noscripts.Location().Filename, gc.Equals, "") 436 c.Check(noscripts.Location().LineNum, gc.Equals, 1) 437 c.Check(noscripts.DeviceNames, gc.DeepEquals, []string{"eth0", "eth1"}) 438 } 439 440 func (s *ParserSuite) TestFailParseDirectoryAsInput(c *gc.C) { 441 stanzas, err := debinterfaces.Parse("testdata/TestInputSourceStanza") 442 c.Assert(err, gc.NotNil) 443 c.Check(err, gc.ErrorMatches, ".* testdata/TestInputSourceStanza: .*") 444 c.Assert(stanzas, gc.IsNil) 445 } 446 447 func (s *ParserSuite) TestSourceStanzaNonExistentFile(c *gc.C) { 448 _, err := debinterfaces.Parse("testdata/TestInputSourceStanza/non-existent-file") 449 c.Assert(err, gc.NotNil) 450 c.Check(err, gc.ErrorMatches, ".* testdata/TestInputSourceStanza/non-existent-file: .*") 451 } 452 453 func (s *ParserSuite) TestSourceStanzaWhereGlobHasZeroMatches(c *gc.C) { 454 stanzas, err := debinterfaces.ParseSource("testdata/TestSourceStanzaWhereGlobHasZeroMatches/interfaces", nil, s.expander) 455 c.Assert(err, gc.IsNil) 456 c.Assert(stanzas, gc.HasLen, 1) 457 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.SourceStanza{}) 458 src := stanzas[0].(debinterfaces.SourceStanza) 459 c.Assert(src.Sources, gc.HasLen, 0) 460 c.Assert(src.Stanzas, gc.HasLen, 0) 461 } 462 463 func (s *ParserSuite) TestSourceStanzaWithRelativeFilenames(c *gc.C) { 464 stanzas, err := debinterfaces.Parse("testdata/TestInputSourceStanza/interfaces") 465 c.Assert(err, gc.IsNil) 466 c.Assert(stanzas, gc.HasLen, 3) 467 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 468 c.Assert(stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 469 c.Assert(stanzas[2], gc.FitsTypeOf, debinterfaces.SourceStanza{}) 470 471 c.Assert(stanzas[0].Location().Filename, gc.Equals, "testdata/TestInputSourceStanza/interfaces") 472 c.Assert(stanzas[0].Location().LineNum, gc.Equals, 5) 473 474 c.Assert(stanzas[1].Location().Filename, gc.Equals, "testdata/TestInputSourceStanza/interfaces") 475 c.Assert(stanzas[1].Location().LineNum, gc.Equals, 6) 476 477 c.Assert(stanzas[2].Location().Filename, gc.Equals, "testdata/TestInputSourceStanza/interfaces") 478 c.Assert(stanzas[2].Location().LineNum, gc.Equals, 12) 479 480 source := stanzas[2].(debinterfaces.SourceStanza) 481 c.Check(source.Path, gc.Equals, "interfaces.d/*.cfg") 482 483 c.Assert(source.Stanzas, gc.HasLen, 6) 484 485 c.Assert(source.Stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 486 c.Assert(source.Stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 487 c.Assert(source.Stanzas[2], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 488 c.Assert(source.Stanzas[3], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 489 c.Assert(source.Stanzas[4], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 490 c.Assert(source.Stanzas[5], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 491 492 basePath := filepath.Join("testdata", "TestInputSourceStanza", "interfaces.d") 493 c.Check(source.Sources, gc.DeepEquals, []string{ 494 filepath.Join(basePath, "eth0.cfg"), 495 filepath.Join(basePath, "eth1.cfg"), 496 filepath.Join(basePath, "eth2.cfg"), 497 }) 498 499 // Note: we don't have tests for stanzas nested > 1 deep. 500 501 eth0 := source.Stanzas[1].(debinterfaces.IfaceStanza) 502 eth1 := source.Stanzas[3].(debinterfaces.IfaceStanza) 503 eth2 := source.Stanzas[5].(debinterfaces.IfaceStanza) 504 505 c.Assert(eth0.Definition(), gc.HasLen, 1) 506 c.Check(eth0.Definition()[0], gc.Equals, "iface eth0 inet dhcp") 507 c.Check(eth0.Location().Filename, gc.Equals, filepath.Join(basePath, "eth0.cfg")) 508 c.Check(eth0.Location().LineNum, gc.Equals, 2) 509 510 c.Assert(eth1.Definition(), gc.HasLen, 3) 511 c.Check(eth1.Definition()[0], gc.Equals, "iface eth1 inet static") 512 c.Check(eth1.Definition()[1], gc.Equals, "address 192.168.1.64") 513 c.Check(eth1.Definition()[2], gc.Equals, "dns-nameservers 192.168.1.254") 514 c.Check(eth1.Location().Filename, gc.Equals, filepath.Join(basePath, "eth1.cfg")) 515 c.Check(eth1.Location().LineNum, gc.Equals, 2) 516 517 c.Assert(eth2.Definition(), gc.HasLen, 1) 518 c.Check(eth2.Definition()[0], gc.Equals, "iface eth2 inet manual") 519 c.Check(eth2.Location().Filename, gc.Equals, filepath.Join(basePath, "eth2.cfg")) 520 c.Check(eth2.Location().LineNum, gc.Equals, 2) 521 } 522 523 func (s *ParserSuite) TestSourceStanzaFromFileWithStanzaErrors(c *gc.C) { 524 _, err := debinterfaces.Parse("testdata/TestInputSourceStanzaWithErrors/interfaces") 525 c.Assert(err, gc.NotNil) 526 c.Assert(err, gc.FitsTypeOf, &debinterfaces.ParseError{}) 527 parseError := err.(*debinterfaces.ParseError) 528 c.Assert(parseError, gc.DeepEquals, &debinterfaces.ParseError{ 529 Filename: filepath.Join("testdata", "TestInputSourceStanzaWithErrors", "interfaces.d", "eth1.cfg"), 530 Line: "iface", 531 LineNum: 2, 532 Message: "missing device name", 533 }) 534 } 535 536 func (s *ParserSuite) TestSourceDirectoryStanzaWithRelativeFilenames(c *gc.C) { 537 stanzas, err := debinterfaces.Parse("testdata/TestInputSourceDirectoryStanza/interfaces") 538 c.Assert(err, gc.IsNil) 539 c.Assert(stanzas, gc.HasLen, 3) 540 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 541 c.Assert(stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 542 c.Assert(stanzas[2], gc.FitsTypeOf, debinterfaces.SourceDirectoryStanza{}) 543 544 c.Assert(stanzas[0].Location().Filename, gc.Equals, "testdata/TestInputSourceDirectoryStanza/interfaces") 545 c.Assert(stanzas[0].Location().LineNum, gc.Equals, 1) 546 547 c.Assert(stanzas[1].Location().Filename, gc.Equals, "testdata/TestInputSourceDirectoryStanza/interfaces") 548 c.Assert(stanzas[1].Location().LineNum, gc.Equals, 2) 549 550 c.Assert(stanzas[2].Location().Filename, gc.Equals, "testdata/TestInputSourceDirectoryStanza/interfaces") 551 c.Assert(stanzas[2].Location().LineNum, gc.Equals, 4) 552 553 source := stanzas[2].(debinterfaces.SourceDirectoryStanza) 554 c.Check(source.Path, gc.Equals, "interfaces.d") 555 556 c.Assert(source.Stanzas, gc.HasLen, 2) 557 558 c.Assert(source.Stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 559 c.Assert(source.Stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 560 561 c.Check(source.Sources, gc.DeepEquals, []string{ 562 filepath.Join("testdata", "TestInputSourceDirectoryStanza", "interfaces.d", "eth3"), 563 }) 564 565 // Note: we don't have tests for stanzas nested > 1 deep. 566 567 eth3 := source.Stanzas[1].(debinterfaces.IfaceStanza) 568 c.Assert(eth3.Definition(), gc.HasLen, 3) 569 c.Check(eth3.Definition()[0], gc.Equals, "iface eth3 inet static") 570 c.Check(eth3.Definition()[1], gc.Equals, "address 192.168.1.128") 571 c.Check(eth3.Definition()[2], gc.Equals, "dns-nameservers 192.168.1.254") 572 c.Check(eth3.Location().Filename, gc.Equals, filepath.Join("testdata", "TestInputSourceDirectoryStanza", "interfaces.d", "eth3")) 573 c.Check(eth3.Location().LineNum, gc.Equals, 2) 574 } 575 576 func (s *ParserSuite) TestSourceDirectoryStanzaFromDirectoryWithStanzaErrors(c *gc.C) { 577 _, err := debinterfaces.Parse("testdata/TestInputSourceDirectoryStanzaWithErrors/interfaces") 578 c.Assert(err, gc.NotNil) 579 c.Assert(err, gc.FitsTypeOf, &debinterfaces.ParseError{}) 580 parseError := err.(*debinterfaces.ParseError) 581 c.Assert(parseError, gc.DeepEquals, &debinterfaces.ParseError{ 582 Filename: filepath.Join("testdata", "TestInputSourceDirectoryStanzaWithErrors", "interfaces.d", "eth3"), 583 Line: "iface", 584 LineNum: 2, 585 Message: "missing device name", 586 }) 587 } 588 589 func (s *ParserSuite) TestSourceStanzaWithWordExpanderError(c *gc.C) { 590 _, err := debinterfaces.ParseSource("testdata/TestInputSourceStanza/interfaces", nil, wordExpanderWithError("boom")) 591 c.Assert(err, gc.NotNil) 592 c.Assert(err, gc.FitsTypeOf, &debinterfaces.ParseError{}) 593 parseError := err.(*debinterfaces.ParseError) 594 c.Assert(parseError, gc.DeepEquals, &debinterfaces.ParseError{ 595 Filename: "testdata/TestInputSourceStanza/interfaces", 596 Line: "source interfaces.d/*.cfg", 597 LineNum: 12, 598 Message: "word expansion failed: boom", 599 }) 600 } 601 602 func (s *ParserSuite) TestSourceDirectoryStanzaWithWordExpanderError(c *gc.C) { 603 _, err := debinterfaces.ParseSource("testdata/TestInputSourceDirectoryStanza/interfaces", nil, wordExpanderWithError("boom")) 604 c.Assert(err, gc.NotNil) 605 c.Assert(err, gc.FitsTypeOf, &debinterfaces.ParseError{}) 606 parseError := err.(*debinterfaces.ParseError) 607 c.Assert(parseError, gc.DeepEquals, &debinterfaces.ParseError{ 608 Filename: "testdata/TestInputSourceDirectoryStanza/interfaces", 609 Line: "source-directory interfaces.d", 610 LineNum: 4, 611 Message: "word expansion failed: boom", 612 }) 613 } 614 615 func (s *ParserSuite) TestSourceStanzaWithAbsoluteFilenames(c *gc.C) { 616 dir, err := os.Getwd() 617 c.Assert(err, jc.ErrorIsNil) 618 fullpath := fmt.Sprintf("%s/testdata/TestInputSourceStanza/interfaces.d/*.cfg", dir) 619 content := fmt.Sprintf("source %s", fullpath) 620 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 621 c.Assert(err, gc.IsNil) 622 c.Assert(stanzas, gc.HasLen, 1) 623 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.SourceStanza{}) 624 625 c.Assert(stanzas[0].Location().Filename, gc.Equals, "") 626 c.Assert(stanzas[0].Location().LineNum, gc.Equals, 1) 627 628 source := stanzas[0].(debinterfaces.SourceStanza) 629 c.Check(source.Path, gc.Equals, fullpath) 630 631 c.Assert(source.Stanzas, gc.HasLen, 6) 632 633 c.Assert(source.Stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 634 c.Assert(source.Stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 635 c.Assert(source.Stanzas[2], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 636 c.Assert(source.Stanzas[3], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 637 c.Assert(source.Stanzas[4], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 638 c.Assert(source.Stanzas[5], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 639 640 c.Check(source.Sources, gc.DeepEquals, []string{ 641 filepath.Join(dir, "testdata/TestInputSourceStanza/interfaces.d/eth0.cfg"), 642 filepath.Join(dir, "testdata/TestInputSourceStanza/interfaces.d/eth1.cfg"), 643 filepath.Join(dir, "testdata/TestInputSourceStanza/interfaces.d/eth2.cfg"), 644 }) 645 646 // Note: we don't have tests for stanzas nested > 1 deep. 647 648 eth0 := source.Stanzas[1].(debinterfaces.IfaceStanza) 649 eth1 := source.Stanzas[3].(debinterfaces.IfaceStanza) 650 eth2 := source.Stanzas[5].(debinterfaces.IfaceStanza) 651 652 c.Assert(eth0.Definition(), gc.HasLen, 1) 653 c.Check(eth0.Definition()[0], gc.Equals, "iface eth0 inet dhcp") 654 c.Check(eth0.Location().Filename, gc.Equals, filepath.Join(dir, "testdata/TestInputSourceStanza/interfaces.d/eth0.cfg")) 655 c.Check(eth0.Location().LineNum, gc.Equals, 2) 656 657 c.Assert(eth1.Definition(), gc.HasLen, 3) 658 c.Check(eth1.Definition()[0], gc.Equals, "iface eth1 inet static") 659 c.Check(eth1.Definition()[1], gc.Equals, "address 192.168.1.64") 660 c.Check(eth1.Definition()[2], gc.Equals, "dns-nameservers 192.168.1.254") 661 c.Check(eth1.Location().Filename, gc.Equals, filepath.Join(dir, "testdata/TestInputSourceStanza/interfaces.d/eth1.cfg")) 662 c.Check(eth1.Location().LineNum, gc.Equals, 2) 663 664 c.Assert(eth2.Definition(), gc.HasLen, 1) 665 c.Check(eth2.Definition()[0], gc.Equals, "iface eth2 inet manual") 666 c.Check(eth2.Location().Filename, gc.Equals, filepath.Join(dir, "testdata/TestInputSourceStanza/interfaces.d/eth2.cfg")) 667 c.Check(eth2.Location().LineNum, gc.Equals, 2) 668 } 669 670 func (s *ParserSuite) TestSourceDirectoryStanzaWithAbsoluteFilenames(c *gc.C) { 671 dir, err := os.Getwd() 672 c.Assert(err, jc.ErrorIsNil) 673 fullpath := fmt.Sprintf("%s/testdata/TestInputSourceDirectoryStanza/interfaces.d", dir) 674 content := fmt.Sprintf("source-directory %s", fullpath) 675 stanzas, err := debinterfaces.ParseSource("", content, s.expander) 676 c.Assert(err, gc.IsNil) 677 c.Assert(stanzas, gc.HasLen, 1) 678 c.Assert(stanzas[0], gc.FitsTypeOf, debinterfaces.SourceDirectoryStanza{}) 679 680 c.Assert(stanzas[0].Location().Filename, gc.Equals, "") 681 c.Assert(stanzas[0].Location().LineNum, gc.Equals, 1) 682 683 source := stanzas[0].(debinterfaces.SourceDirectoryStanza) 684 c.Check(source.Path, gc.Equals, fullpath) 685 686 c.Assert(source.Stanzas, gc.HasLen, 2) 687 688 c.Assert(source.Stanzas[0], gc.FitsTypeOf, debinterfaces.AutoStanza{}) 689 c.Assert(source.Stanzas[1], gc.FitsTypeOf, debinterfaces.IfaceStanza{}) 690 691 c.Check(source.Sources, gc.DeepEquals, []string{ 692 filepath.Join(fullpath, "eth3"), 693 }) 694 695 // Note: we don't have tests for source directory stanzas nested > 1 deep. 696 697 eth3 := source.Stanzas[1].(debinterfaces.IfaceStanza) 698 c.Assert(eth3.Definition(), gc.HasLen, 3) 699 c.Check(eth3.Definition()[0], gc.Equals, "iface eth3 inet static") 700 c.Check(eth3.Definition()[1], gc.Equals, "address 192.168.1.128") 701 c.Check(eth3.Definition()[2], gc.Equals, "dns-nameservers 192.168.1.254") 702 c.Check(eth3.Location().Filename, gc.Equals, filepath.Join(fullpath, "eth3")) 703 c.Check(eth3.Location().LineNum, gc.Equals, 2) 704 } 705 706 func (s *ParserSuite) TestSourceStanzaWithAbsoluteNonExistentFilenames(c *gc.C) { 707 dir, err := os.Getwd() 708 c.Assert(err, jc.ErrorIsNil) 709 fullpath := fmt.Sprintf("%s/testdata/non-existent.d/*", dir) 710 content := fmt.Sprintf("source %s", fullpath) 711 _, err = debinterfaces.ParseSource("", content, s.expander) 712 c.Assert(err, gc.IsNil) 713 } 714 715 func (s *ParserSuite) TestSourceDirectoryStanzaWithAbsoluteNonExistentFilenames(c *gc.C) { 716 dir, err := os.Getwd() 717 c.Assert(err, jc.ErrorIsNil) 718 fullpath := fmt.Sprintf("%s/testdata/non-existent", dir) 719 content := fmt.Sprintf("source-directory %s", fullpath) 720 _, err = debinterfaces.ParseSource("", content, s.expander) 721 c.Assert(err, gc.NotNil) 722 } 723 724 func (s *ParserSuite) TestIfupdownPackageExample(c *gc.C) { 725 _, err := debinterfaces.ParseSource("testdata/ifupdown-examples", nil, s.expander) 726 c.Assert(err, gc.IsNil) 727 }