github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/provider/dummy/environs_test.go (about)

     1  // Copyright 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package dummy_test
     5  
     6  import (
     7  	"net"
     8  	"strings"
     9  	stdtesting "testing"
    10  	"time"
    11  
    12  	"github.com/juju/errors"
    13  	gitjujutesting "github.com/juju/testing"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/environs"
    18  	"github.com/juju/juju/environs/bootstrap"
    19  	"github.com/juju/juju/environs/config"
    20  	"github.com/juju/juju/environs/jujutest"
    21  	envtesting "github.com/juju/juju/environs/testing"
    22  	"github.com/juju/juju/feature"
    23  	"github.com/juju/juju/instance"
    24  	jujutesting "github.com/juju/juju/juju/testing"
    25  	"github.com/juju/juju/network"
    26  	"github.com/juju/juju/provider/dummy"
    27  	"github.com/juju/juju/testing"
    28  	"github.com/juju/juju/version"
    29  )
    30  
    31  func TestPackage(t *stdtesting.T) {
    32  	testing.MgoTestPackage(t)
    33  }
    34  
    35  func init() {
    36  	gc.Suite(&liveSuite{
    37  		LiveTests: jujutest.LiveTests{
    38  			TestConfig:     dummy.SampleConfig(),
    39  			CanOpenState:   true,
    40  			HasProvisioner: false,
    41  		},
    42  	})
    43  	gc.Suite(&suite{
    44  		Tests: jujutest.Tests{
    45  			TestConfig: dummy.SampleConfig(),
    46  		},
    47  	})
    48  }
    49  
    50  type liveSuite struct {
    51  	testing.BaseSuite
    52  	gitjujutesting.MgoSuite
    53  	jujutest.LiveTests
    54  }
    55  
    56  func (s *liveSuite) SetUpSuite(c *gc.C) {
    57  	s.BaseSuite.SetUpSuite(c)
    58  	s.MgoSuite.SetUpSuite(c)
    59  	s.LiveTests.SetUpSuite(c)
    60  }
    61  
    62  func (s *liveSuite) TearDownSuite(c *gc.C) {
    63  	s.LiveTests.TearDownSuite(c)
    64  	s.MgoSuite.TearDownSuite(c)
    65  	s.BaseSuite.TearDownSuite(c)
    66  }
    67  
    68  func (s *liveSuite) SetUpTest(c *gc.C) {
    69  	s.BaseSuite.SetUpTest(c)
    70  	s.SetFeatureFlags(feature.AddressAllocation)
    71  	s.MgoSuite.SetUpTest(c)
    72  	s.LiveTests.SetUpTest(c)
    73  }
    74  
    75  func (s *liveSuite) TearDownTest(c *gc.C) {
    76  	s.Destroy(c)
    77  	s.LiveTests.TearDownTest(c)
    78  	s.MgoSuite.TearDownTest(c)
    79  	s.BaseSuite.TearDownTest(c)
    80  }
    81  
    82  type suite struct {
    83  	testing.BaseSuite
    84  	gitjujutesting.MgoSuite
    85  	jujutest.Tests
    86  }
    87  
    88  func (s *suite) SetUpSuite(c *gc.C) {
    89  	s.BaseSuite.SetUpSuite(c)
    90  	s.MgoSuite.SetUpSuite(c)
    91  }
    92  
    93  func (s *suite) TearDownSuite(c *gc.C) {
    94  	s.MgoSuite.TearDownSuite(c)
    95  	s.BaseSuite.TearDownSuite(c)
    96  }
    97  
    98  func (s *suite) SetUpTest(c *gc.C) {
    99  	s.BaseSuite.SetUpTest(c)
   100  	s.SetFeatureFlags(feature.AddressAllocation)
   101  	s.PatchValue(&version.Current.Number, testing.FakeVersionNumber)
   102  	s.MgoSuite.SetUpTest(c)
   103  	s.Tests.SetUpTest(c)
   104  }
   105  
   106  func (s *suite) TearDownTest(c *gc.C) {
   107  	s.Tests.TearDownTest(c)
   108  	s.MgoSuite.TearDownTest(c)
   109  	dummy.Reset()
   110  	s.BaseSuite.TearDownTest(c)
   111  }
   112  
   113  func (s *suite) bootstrapTestEnviron(c *gc.C, preferIPv6 bool) environs.NetworkingEnviron {
   114  	s.TestConfig["prefer-ipv6"] = preferIPv6
   115  	cfg, err := config.New(config.NoDefaults, s.TestConfig)
   116  	c.Assert(err, jc.ErrorIsNil)
   117  	env, err := environs.Prepare(cfg, envtesting.BootstrapContext(c), s.ConfigStore)
   118  	c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", s.TestConfig))
   119  	c.Assert(env, gc.NotNil)
   120  	netenv, supported := environs.SupportsNetworking(env)
   121  	c.Assert(supported, jc.IsTrue)
   122  
   123  	err = bootstrap.EnsureNotBootstrapped(netenv)
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	err = bootstrap.Bootstrap(envtesting.BootstrapContext(c), netenv, bootstrap.BootstrapParams{})
   126  	c.Assert(err, jc.ErrorIsNil)
   127  	return netenv
   128  }
   129  
   130  func (s *suite) TestAvailabilityZone(c *gc.C) {
   131  	e := s.bootstrapTestEnviron(c, true)
   132  	defer func() {
   133  		err := e.Destroy()
   134  		c.Assert(err, jc.ErrorIsNil)
   135  	}()
   136  
   137  	inst, hwc := jujutesting.AssertStartInstance(c, e, "0")
   138  	c.Assert(inst, gc.NotNil)
   139  	c.Check(hwc.AvailabilityZone, gc.IsNil)
   140  }
   141  
   142  func (s *suite) TestSupportsAddressAllocation(c *gc.C) {
   143  	e := s.bootstrapTestEnviron(c, false)
   144  	defer func() {
   145  		err := e.Destroy()
   146  		c.Assert(err, jc.ErrorIsNil)
   147  	}()
   148  
   149  	// By default, it's supported.
   150  	supported, err := e.SupportsAddressAllocation("any-id")
   151  	c.Assert(err, jc.ErrorIsNil)
   152  	c.Assert(supported, jc.IsTrue)
   153  
   154  	// Any subnet id with prefix "noalloc-" simulates address
   155  	// allocation is not supported.
   156  	supported, err = e.SupportsAddressAllocation("noalloc-foo")
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	c.Assert(supported, jc.IsFalse)
   159  
   160  	// Test we can induce an error for SupportsAddressAllocation.
   161  	s.breakMethods(c, e, "SupportsAddressAllocation")
   162  	supported, err = e.SupportsAddressAllocation("any-id")
   163  	c.Assert(err, gc.ErrorMatches, `dummy\.SupportsAddressAllocation is broken`)
   164  	c.Assert(supported, jc.IsFalse)
   165  
   166  	// Finally, test the method respects the feature flag when
   167  	// disabled.
   168  	s.SetFeatureFlags() // clear the flags.
   169  	supported, err = e.SupportsAddressAllocation("any-id")
   170  	c.Assert(err, gc.ErrorMatches, "address allocation not supported")
   171  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   172  	c.Assert(supported, jc.IsFalse)
   173  }
   174  
   175  func (s *suite) breakMethods(c *gc.C, e environs.NetworkingEnviron, names ...string) {
   176  	cfg := e.Config()
   177  	brokenCfg, err := cfg.Apply(map[string]interface{}{
   178  		"broken": strings.Join(names, " "),
   179  	})
   180  	c.Assert(err, jc.ErrorIsNil)
   181  	err = e.SetConfig(brokenCfg)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  }
   184  
   185  func (s *suite) TestAllocateAddress(c *gc.C) {
   186  	e := s.bootstrapTestEnviron(c, false)
   187  	defer func() {
   188  		err := e.Destroy()
   189  		c.Assert(err, jc.ErrorIsNil)
   190  	}()
   191  
   192  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   193  	c.Assert(inst, gc.NotNil)
   194  	subnetId := network.Id("net1")
   195  
   196  	opc := make(chan dummy.Operation, 200)
   197  	dummy.Listen(opc)
   198  
   199  	// Test allocating a couple of addresses.
   200  	newAddress := network.NewScopedAddress("0.1.2.1", network.ScopeCloudLocal)
   201  	err := e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   202  	c.Assert(err, jc.ErrorIsNil)
   203  	assertAllocateAddress(c, e, opc, inst.Id(), subnetId, newAddress, "foo", "bar")
   204  
   205  	newAddress = network.NewScopedAddress("0.1.2.2", network.ScopeCloudLocal)
   206  	err = e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	assertAllocateAddress(c, e, opc, inst.Id(), subnetId, newAddress, "foo", "bar")
   209  
   210  	// Test we can induce errors.
   211  	s.breakMethods(c, e, "AllocateAddress")
   212  	newAddress = network.NewScopedAddress("0.1.2.3", network.ScopeCloudLocal)
   213  	err = e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   214  	c.Assert(err, gc.ErrorMatches, `dummy\.AllocateAddress is broken`)
   215  
   216  	// Finally, test the method respects the feature flag when
   217  	// disabled.
   218  	s.SetFeatureFlags() // clear the flags.
   219  	err = e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   220  	c.Assert(err, gc.ErrorMatches, "address allocation not supported")
   221  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   222  }
   223  
   224  func (s *suite) TestReleaseAddress(c *gc.C) {
   225  	e := s.bootstrapTestEnviron(c, false)
   226  	defer func() {
   227  		err := e.Destroy()
   228  		c.Assert(err, jc.ErrorIsNil)
   229  	}()
   230  
   231  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   232  	c.Assert(inst, gc.NotNil)
   233  	subnetId := network.Id("net1")
   234  
   235  	opc := make(chan dummy.Operation, 200)
   236  	dummy.Listen(opc)
   237  
   238  	// Release a couple of addresses.
   239  	address := network.NewScopedAddress("0.1.2.1", network.ScopeCloudLocal)
   240  	macAddress := "foobar"
   241  	err := e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   242  	c.Assert(err, jc.ErrorIsNil)
   243  	assertReleaseAddress(c, e, opc, inst.Id(), subnetId, address, macAddress)
   244  
   245  	address = network.NewScopedAddress("0.1.2.2", network.ScopeCloudLocal)
   246  	err = e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   247  	c.Assert(err, jc.ErrorIsNil)
   248  	assertReleaseAddress(c, e, opc, inst.Id(), subnetId, address, macAddress)
   249  
   250  	// Test we can induce errors.
   251  	s.breakMethods(c, e, "ReleaseAddress")
   252  	address = network.NewScopedAddress("0.1.2.3", network.ScopeCloudLocal)
   253  	err = e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   254  	c.Assert(err, gc.ErrorMatches, `dummy\.ReleaseAddress is broken`)
   255  
   256  	// Finally, test the method respects the feature flag when
   257  	// disabled.
   258  	s.SetFeatureFlags() // clear the flags.
   259  	err = e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   260  	c.Assert(err, gc.ErrorMatches, "address allocation not supported")
   261  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   262  }
   263  
   264  func (s *suite) TestNetworkInterfaces(c *gc.C) {
   265  	e := s.bootstrapTestEnviron(c, false)
   266  	defer func() {
   267  		err := e.Destroy()
   268  		c.Assert(err, jc.ErrorIsNil)
   269  	}()
   270  
   271  	opc := make(chan dummy.Operation, 200)
   272  	dummy.Listen(opc)
   273  
   274  	expectInfo := []network.InterfaceInfo{{
   275  		ProviderId:       "dummy-eth0",
   276  		ProviderSubnetId: "dummy-private",
   277  		NetworkName:      "juju-private",
   278  		CIDR:             "0.10.0.0/24",
   279  		DeviceIndex:      0,
   280  		InterfaceName:    "eth0",
   281  		VLANTag:          0,
   282  		MACAddress:       "aa:bb:cc:dd:ee:f0",
   283  		Disabled:         false,
   284  		NoAutoStart:      false,
   285  		ConfigType:       network.ConfigDHCP,
   286  		Address:          network.NewAddress("0.10.0.2"),
   287  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   288  		GatewayAddress:   network.NewAddress("0.10.0.1"),
   289  		ExtraConfig:      nil,
   290  	}, {
   291  		ProviderId:       "dummy-eth1",
   292  		ProviderSubnetId: "dummy-public",
   293  		NetworkName:      "juju-public",
   294  		CIDR:             "0.20.0.0/24",
   295  		DeviceIndex:      1,
   296  		InterfaceName:    "eth1",
   297  		VLANTag:          1,
   298  		MACAddress:       "aa:bb:cc:dd:ee:f1",
   299  		Disabled:         false,
   300  		NoAutoStart:      true,
   301  		ConfigType:       network.ConfigDHCP,
   302  		Address:          network.NewAddress("0.20.0.2"),
   303  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   304  		GatewayAddress:   network.NewAddress("0.20.0.1"),
   305  		ExtraConfig:      nil,
   306  	}, {
   307  		ProviderId:       "dummy-eth2",
   308  		ProviderSubnetId: "dummy-disabled",
   309  		NetworkName:      "juju-disabled",
   310  		CIDR:             "0.30.0.0/24",
   311  		DeviceIndex:      2,
   312  		InterfaceName:    "eth2",
   313  		VLANTag:          2,
   314  		MACAddress:       "aa:bb:cc:dd:ee:f2",
   315  		Disabled:         true,
   316  		NoAutoStart:      false,
   317  		ConfigType:       network.ConfigDHCP,
   318  		Address:          network.NewAddress("0.30.0.2"),
   319  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   320  		GatewayAddress:   network.NewAddress("0.30.0.1"),
   321  		ExtraConfig:      nil,
   322  	}}
   323  	info, err := e.NetworkInterfaces("i-42")
   324  	c.Assert(err, jc.ErrorIsNil)
   325  	c.Assert(info, jc.DeepEquals, expectInfo)
   326  	assertInterfaces(c, e, opc, "i-42", expectInfo)
   327  
   328  	// Test that with instance id prefix "i-no-nics-" no results are
   329  	// returned.
   330  	info, err = e.NetworkInterfaces("i-no-nics-here")
   331  	c.Assert(err, jc.ErrorIsNil)
   332  	c.Assert(info, gc.HasLen, 0)
   333  	assertInterfaces(c, e, opc, "i-no-nics-here", expectInfo[:0])
   334  
   335  	// Test that with instance id prefix "i-nic-no-subnet-" we get a result
   336  	// with no associated subnet.
   337  	expectInfo = []network.InterfaceInfo{{
   338  		DeviceIndex:   0,
   339  		ProviderId:    network.Id("dummy-eth0"),
   340  		NetworkName:   "juju-public",
   341  		InterfaceName: "eth0",
   342  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   343  		Disabled:      false,
   344  		NoAutoStart:   false,
   345  		ConfigType:    network.ConfigDHCP,
   346  	}}
   347  	info, err = e.NetworkInterfaces("i-nic-no-subnet-here")
   348  	c.Assert(err, jc.ErrorIsNil)
   349  	c.Assert(info, gc.HasLen, 1)
   350  	assertInterfaces(c, e, opc, "i-nic-no-subnet-here", expectInfo)
   351  
   352  	// Test that with instance id prefix "i-disabled-nic-" we get a result
   353  	// with only a disabled subnet.
   354  	expectInfo = []network.InterfaceInfo{{
   355  		ProviderId:       "dummy-eth2",
   356  		ProviderSubnetId: "dummy-disabled",
   357  		NetworkName:      "juju-disabled",
   358  		CIDR:             "0.30.0.0/24",
   359  		DeviceIndex:      2,
   360  		InterfaceName:    "eth2",
   361  		VLANTag:          2,
   362  		MACAddress:       "aa:bb:cc:dd:ee:f2",
   363  		Disabled:         true,
   364  		NoAutoStart:      false,
   365  		ConfigType:       network.ConfigDHCP,
   366  		Address:          network.NewAddress("0.30.0.2"),
   367  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   368  		GatewayAddress:   network.NewAddress("0.30.0.1"),
   369  		ExtraConfig:      nil,
   370  	}}
   371  	info, err = e.NetworkInterfaces("i-disabled-nic-here")
   372  	c.Assert(err, jc.ErrorIsNil)
   373  	c.Assert(info, gc.HasLen, 1)
   374  	assertInterfaces(c, e, opc, "i-disabled-nic-here", expectInfo)
   375  
   376  	// Test we can induce errors.
   377  	s.breakMethods(c, e, "NetworkInterfaces")
   378  	info, err = e.NetworkInterfaces("i-any")
   379  	c.Assert(err, gc.ErrorMatches, `dummy\.NetworkInterfaces is broken`)
   380  	c.Assert(info, gc.HasLen, 0)
   381  }
   382  
   383  func (s *suite) TestSubnets(c *gc.C) {
   384  	e := s.bootstrapTestEnviron(c, false)
   385  	defer func() {
   386  		err := e.Destroy()
   387  		c.Assert(err, jc.ErrorIsNil)
   388  	}()
   389  
   390  	opc := make(chan dummy.Operation, 200)
   391  	dummy.Listen(opc)
   392  
   393  	expectInfo := []network.SubnetInfo{{
   394  		CIDR:              "0.10.0.0/24",
   395  		ProviderId:        "dummy-private",
   396  		AllocatableIPLow:  net.ParseIP("0.10.0.0"),
   397  		AllocatableIPHigh: net.ParseIP("0.10.0.255"),
   398  		AvailabilityZones: []string{"zone1", "zone2"},
   399  	}, {
   400  		CIDR:              "0.20.0.0/24",
   401  		ProviderId:        "dummy-public",
   402  		AllocatableIPLow:  net.ParseIP("0.20.0.0"),
   403  		AllocatableIPHigh: net.ParseIP("0.20.0.255"),
   404  	}}
   405  	// Prepare a version of the above with no allocatable range to
   406  	// test the magic "i-no-alloc-" prefix below.
   407  	noallocInfo := make([]network.SubnetInfo, len(expectInfo))
   408  	for i, exp := range expectInfo {
   409  		pid := string(exp.ProviderId)
   410  		pid = strings.TrimPrefix(pid, "dummy-")
   411  		noallocInfo[i].ProviderId = network.Id("noalloc-" + pid)
   412  		noallocInfo[i].AllocatableIPLow = nil
   413  		noallocInfo[i].AllocatableIPHigh = nil
   414  		noallocInfo[i].AvailabilityZones = exp.AvailabilityZones
   415  		noallocInfo[i].CIDR = exp.CIDR
   416  	}
   417  
   418  	ids := []network.Id{"dummy-private", "dummy-public", "foo-bar"}
   419  	netInfo, err := e.Subnets("i-foo", ids)
   420  	c.Assert(err, jc.ErrorIsNil)
   421  	c.Assert(netInfo, jc.DeepEquals, expectInfo)
   422  	assertSubnets(c, e, opc, "i-foo", ids, expectInfo)
   423  
   424  	// Test filtering by id(s).
   425  	netInfo, err = e.Subnets("i-foo", nil)
   426  	c.Assert(err, jc.ErrorIsNil)
   427  	c.Assert(netInfo, jc.DeepEquals, expectInfo)
   428  	assertSubnets(c, e, opc, "i-foo", nil, expectInfo)
   429  	netInfo, err = e.Subnets("i-foo", ids[0:1])
   430  	c.Assert(err, jc.ErrorIsNil)
   431  	c.Assert(netInfo, jc.DeepEquals, expectInfo[0:1])
   432  	assertSubnets(c, e, opc, "i-foo", ids[0:1], expectInfo[0:1])
   433  	netInfo, err = e.Subnets("i-foo", ids[1:])
   434  	c.Assert(err, jc.ErrorIsNil)
   435  	c.Assert(netInfo, jc.DeepEquals, expectInfo[1:])
   436  	assertSubnets(c, e, opc, "i-foo", ids[1:], expectInfo[1:])
   437  
   438  	// Test that using an instance id with prefix of either
   439  	// "i-no-subnets-" or "i-nic-no-subnet-"
   440  	// returns no results, regardless whether ids are given or not.
   441  	for _, instId := range []instance.Id{"i-no-subnets-foo", "i-nic-no-subnet-foo"} {
   442  		netInfo, err = e.Subnets(instId, nil)
   443  		c.Assert(err, jc.ErrorIsNil)
   444  		c.Assert(netInfo, gc.HasLen, 0)
   445  		assertSubnets(c, e, opc, instId, nil, expectInfo[:0])
   446  	}
   447  
   448  	netInfo, err = e.Subnets("i-no-subnets-foo", ids)
   449  	c.Assert(err, jc.ErrorIsNil)
   450  	c.Assert(netInfo, gc.HasLen, 0)
   451  	assertSubnets(c, e, opc, "i-no-subnets-foo", ids, expectInfo[:0])
   452  
   453  	// Test the behavior with "i-no-alloc-" instance id prefix.
   454  	// When # is "all", all returned subnets have no allocatable range
   455  	// set and have provider ids with "noalloc-" prefix.
   456  	netInfo, err = e.Subnets("i-no-alloc-all", nil)
   457  	c.Assert(err, jc.ErrorIsNil)
   458  	c.Assert(netInfo, jc.DeepEquals, noallocInfo)
   459  	assertSubnets(c, e, opc, "i-no-alloc-all", nil, noallocInfo)
   460  
   461  	// When # is an integer, the #-th subnet in result has no
   462  	// allocatable range set and a provider id prefix "noalloc-".
   463  	netInfo, err = e.Subnets("i-no-alloc-0", nil)
   464  	c.Assert(err, jc.ErrorIsNil)
   465  	expectResult := []network.SubnetInfo{noallocInfo[0], expectInfo[1]}
   466  	c.Assert(netInfo, jc.DeepEquals, expectResult)
   467  	assertSubnets(c, e, opc, "i-no-alloc-0", nil, expectResult)
   468  
   469  	netInfo, err = e.Subnets("i-no-alloc-1", nil)
   470  	c.Assert(err, jc.ErrorIsNil)
   471  	expectResult = []network.SubnetInfo{expectInfo[0], noallocInfo[1]}
   472  	c.Assert(netInfo, jc.DeepEquals, expectResult)
   473  	assertSubnets(c, e, opc, "i-no-alloc-1", nil, expectResult)
   474  
   475  	// For the last case above, also test the error returned when # is
   476  	// not integer or it's out of range of the results (including when
   477  	// filtering by ids is applied).
   478  	netInfo, err = e.Subnets("i-no-alloc-foo", nil)
   479  	c.Assert(err, gc.ErrorMatches, `invalid index "foo"; expected int`)
   480  	c.Assert(netInfo, gc.HasLen, 0)
   481  
   482  	netInfo, err = e.Subnets("i-no-alloc-1", ids[:1])
   483  	c.Assert(err, gc.ErrorMatches, `index 1 out of range; expected 0..0`)
   484  	c.Assert(netInfo, gc.HasLen, 0)
   485  
   486  	netInfo, err = e.Subnets("i-no-alloc-2", ids)
   487  	c.Assert(err, gc.ErrorMatches, `index 2 out of range; expected 0..1`)
   488  	c.Assert(netInfo, gc.HasLen, 0)
   489  
   490  	// Test we can induce errors.
   491  	s.breakMethods(c, e, "Subnets")
   492  	netInfo, err = e.Subnets("i-any", nil)
   493  	c.Assert(err, gc.ErrorMatches, `dummy\.Subnets is broken`)
   494  	c.Assert(netInfo, gc.HasLen, 0)
   495  }
   496  
   497  func (s *suite) TestPreferIPv6On(c *gc.C) {
   498  	e := s.bootstrapTestEnviron(c, true)
   499  	defer func() {
   500  		err := e.Destroy()
   501  		c.Assert(err, jc.ErrorIsNil)
   502  	}()
   503  
   504  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   505  	c.Assert(inst, gc.NotNil)
   506  	addrs, err := inst.Addresses()
   507  	c.Assert(err, jc.ErrorIsNil)
   508  	c.Assert(addrs, jc.DeepEquals, network.NewAddresses("only-0.dns", "127.0.0.1", "fc00::1"))
   509  }
   510  
   511  func (s *suite) TestPreferIPv6Off(c *gc.C) {
   512  	e := s.bootstrapTestEnviron(c, false)
   513  	defer func() {
   514  		err := e.Destroy()
   515  		c.Assert(err, jc.ErrorIsNil)
   516  	}()
   517  
   518  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   519  	c.Assert(inst, gc.NotNil)
   520  	addrs, err := inst.Addresses()
   521  	c.Assert(err, jc.ErrorIsNil)
   522  	c.Assert(addrs, jc.DeepEquals, network.NewAddresses("only-0.dns", "127.0.0.1"))
   523  }
   524  
   525  func assertAllocateAddress(c *gc.C, e environs.Environ, opc chan dummy.Operation, expectInstId instance.Id, expectSubnetId network.Id, expectAddress network.Address, expectMAC, expectHostName string) {
   526  	select {
   527  	case op := <-opc:
   528  		addrOp, ok := op.(dummy.OpAllocateAddress)
   529  		if !ok {
   530  			c.Fatalf("unexpected op: %#v", op)
   531  		}
   532  		c.Check(addrOp.SubnetId, gc.Equals, expectSubnetId)
   533  		c.Check(addrOp.InstanceId, gc.Equals, expectInstId)
   534  		c.Check(addrOp.Address, gc.Equals, expectAddress)
   535  		c.Check(addrOp.MACAddress, gc.Equals, expectMAC)
   536  		c.Check(addrOp.HostName, gc.Equals, expectHostName)
   537  		return
   538  	case <-time.After(testing.ShortWait):
   539  		c.Fatalf("time out wating for operation")
   540  	}
   541  }
   542  
   543  func assertReleaseAddress(c *gc.C, e environs.Environ, opc chan dummy.Operation, expectInstId instance.Id, expectSubnetId network.Id, expectAddress network.Address, macAddress string) {
   544  	select {
   545  	case op := <-opc:
   546  		addrOp, ok := op.(dummy.OpReleaseAddress)
   547  		if !ok {
   548  			c.Fatalf("unexpected op: %#v", op)
   549  		}
   550  		c.Check(addrOp.SubnetId, gc.Equals, expectSubnetId)
   551  		c.Check(addrOp.InstanceId, gc.Equals, expectInstId)
   552  		c.Check(addrOp.Address, gc.Equals, expectAddress)
   553  		c.Check(addrOp.MACAddress, gc.Equals, macAddress)
   554  		return
   555  	case <-time.After(testing.ShortWait):
   556  		c.Fatalf("time out wating for operation")
   557  	}
   558  }
   559  
   560  func assertInterfaces(c *gc.C, e environs.Environ, opc chan dummy.Operation, expectInstId instance.Id, expectInfo []network.InterfaceInfo) {
   561  	select {
   562  	case op := <-opc:
   563  		netOp, ok := op.(dummy.OpNetworkInterfaces)
   564  		if !ok {
   565  			c.Fatalf("unexpected op: %#v", op)
   566  		}
   567  		c.Check(netOp.Env, gc.Equals, e.Config().Name())
   568  		c.Check(netOp.InstanceId, gc.Equals, expectInstId)
   569  		c.Check(netOp.Info, jc.DeepEquals, expectInfo)
   570  		return
   571  	case <-time.After(testing.ShortWait):
   572  		c.Fatalf("time out wating for operation")
   573  	}
   574  }
   575  
   576  func assertSubnets(
   577  	c *gc.C,
   578  	e environs.Environ,
   579  	opc chan dummy.Operation,
   580  	instId instance.Id,
   581  	subnetIds []network.Id,
   582  	expectInfo []network.SubnetInfo,
   583  ) {
   584  	select {
   585  	case op := <-opc:
   586  		netOp, ok := op.(dummy.OpSubnets)
   587  		if !ok {
   588  			c.Fatalf("unexpected op: %#v", op)
   589  		}
   590  		c.Check(netOp.InstanceId, gc.Equals, instId)
   591  		c.Check(netOp.SubnetIds, jc.DeepEquals, subnetIds)
   592  		c.Check(netOp.Info, jc.DeepEquals, expectInfo)
   593  		return
   594  	case <-time.After(testing.ShortWait):
   595  		c.Fatalf("time out wating for operation")
   596  	}
   597  }