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