github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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) TestSupportsSpaces(c *gc.C) {
   176  	e := s.bootstrapTestEnviron(c, false)
   177  	defer func() {
   178  		err := e.Destroy()
   179  		c.Assert(err, jc.ErrorIsNil)
   180  	}()
   181  
   182  	// Without change spaces are supported.
   183  	ok, err := e.SupportsSpaces()
   184  	c.Assert(ok, jc.IsTrue)
   185  	c.Assert(err, jc.ErrorIsNil)
   186  
   187  	// Now turn it off.
   188  	isEnabled := dummy.SetSupportsSpaces(false)
   189  	c.Assert(isEnabled, jc.IsTrue)
   190  	ok, err = e.SupportsSpaces()
   191  	c.Assert(ok, jc.IsFalse)
   192  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   193  
   194  	// And finally turn it on again.
   195  	isEnabled = dummy.SetSupportsSpaces(true)
   196  	c.Assert(isEnabled, jc.IsFalse)
   197  	ok, err = e.SupportsSpaces()
   198  	c.Assert(ok, jc.IsTrue)
   199  	c.Assert(err, jc.ErrorIsNil)
   200  }
   201  
   202  func (s *suite) breakMethods(c *gc.C, e environs.NetworkingEnviron, names ...string) {
   203  	cfg := e.Config()
   204  	brokenCfg, err := cfg.Apply(map[string]interface{}{
   205  		"broken": strings.Join(names, " "),
   206  	})
   207  	c.Assert(err, jc.ErrorIsNil)
   208  	err = e.SetConfig(brokenCfg)
   209  	c.Assert(err, jc.ErrorIsNil)
   210  }
   211  
   212  func (s *suite) TestAllocateAddress(c *gc.C) {
   213  	e := s.bootstrapTestEnviron(c, false)
   214  	defer func() {
   215  		err := e.Destroy()
   216  		c.Assert(err, jc.ErrorIsNil)
   217  	}()
   218  
   219  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   220  	c.Assert(inst, gc.NotNil)
   221  	subnetId := network.Id("net1")
   222  
   223  	opc := make(chan dummy.Operation, 200)
   224  	dummy.Listen(opc)
   225  
   226  	// Test allocating a couple of addresses.
   227  	newAddress := network.NewScopedAddress("0.1.2.1", network.ScopeCloudLocal)
   228  	err := e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   229  	c.Assert(err, jc.ErrorIsNil)
   230  	assertAllocateAddress(c, e, opc, inst.Id(), subnetId, newAddress, "foo", "bar")
   231  
   232  	newAddress = network.NewScopedAddress("0.1.2.2", network.ScopeCloudLocal)
   233  	err = e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   234  	c.Assert(err, jc.ErrorIsNil)
   235  	assertAllocateAddress(c, e, opc, inst.Id(), subnetId, newAddress, "foo", "bar")
   236  
   237  	// Test we can induce errors.
   238  	s.breakMethods(c, e, "AllocateAddress")
   239  	newAddress = network.NewScopedAddress("0.1.2.3", network.ScopeCloudLocal)
   240  	err = e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   241  	c.Assert(err, gc.ErrorMatches, `dummy\.AllocateAddress is broken`)
   242  
   243  	// Finally, test the method respects the feature flag when
   244  	// disabled.
   245  	s.SetFeatureFlags() // clear the flags.
   246  	err = e.AllocateAddress(inst.Id(), subnetId, newAddress, "foo", "bar")
   247  	c.Assert(err, gc.ErrorMatches, "address allocation not supported")
   248  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   249  }
   250  
   251  func (s *suite) TestReleaseAddress(c *gc.C) {
   252  	e := s.bootstrapTestEnviron(c, false)
   253  	defer func() {
   254  		err := e.Destroy()
   255  		c.Assert(err, jc.ErrorIsNil)
   256  	}()
   257  
   258  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   259  	c.Assert(inst, gc.NotNil)
   260  	subnetId := network.Id("net1")
   261  
   262  	opc := make(chan dummy.Operation, 200)
   263  	dummy.Listen(opc)
   264  
   265  	// Release a couple of addresses.
   266  	address := network.NewScopedAddress("0.1.2.1", network.ScopeCloudLocal)
   267  	macAddress := "foobar"
   268  	err := e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   269  	c.Assert(err, jc.ErrorIsNil)
   270  	assertReleaseAddress(c, e, opc, inst.Id(), subnetId, address, macAddress)
   271  
   272  	address = network.NewScopedAddress("0.1.2.2", network.ScopeCloudLocal)
   273  	err = e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   274  	c.Assert(err, jc.ErrorIsNil)
   275  	assertReleaseAddress(c, e, opc, inst.Id(), subnetId, address, macAddress)
   276  
   277  	// Test we can induce errors.
   278  	s.breakMethods(c, e, "ReleaseAddress")
   279  	address = network.NewScopedAddress("0.1.2.3", network.ScopeCloudLocal)
   280  	err = e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   281  	c.Assert(err, gc.ErrorMatches, `dummy\.ReleaseAddress is broken`)
   282  
   283  	// Finally, test the method respects the feature flag when
   284  	// disabled.
   285  	s.SetFeatureFlags() // clear the flags.
   286  	err = e.ReleaseAddress(inst.Id(), subnetId, address, macAddress)
   287  	c.Assert(err, gc.ErrorMatches, "address allocation not supported")
   288  	c.Assert(err, jc.Satisfies, errors.IsNotSupported)
   289  }
   290  
   291  func (s *suite) TestNetworkInterfaces(c *gc.C) {
   292  	e := s.bootstrapTestEnviron(c, false)
   293  	defer func() {
   294  		err := e.Destroy()
   295  		c.Assert(err, jc.ErrorIsNil)
   296  	}()
   297  
   298  	opc := make(chan dummy.Operation, 200)
   299  	dummy.Listen(opc)
   300  
   301  	expectInfo := []network.InterfaceInfo{{
   302  		ProviderId:       "dummy-eth0",
   303  		ProviderSubnetId: "dummy-private",
   304  		NetworkName:      "juju-private",
   305  		CIDR:             "0.10.0.0/24",
   306  		DeviceIndex:      0,
   307  		InterfaceName:    "eth0",
   308  		VLANTag:          0,
   309  		MACAddress:       "aa:bb:cc:dd:ee:f0",
   310  		Disabled:         false,
   311  		NoAutoStart:      false,
   312  		ConfigType:       network.ConfigDHCP,
   313  		Address:          network.NewAddress("0.10.0.2"),
   314  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   315  		GatewayAddress:   network.NewAddress("0.10.0.1"),
   316  		ExtraConfig:      nil,
   317  	}, {
   318  		ProviderId:       "dummy-eth1",
   319  		ProviderSubnetId: "dummy-public",
   320  		NetworkName:      "juju-public",
   321  		CIDR:             "0.20.0.0/24",
   322  		DeviceIndex:      1,
   323  		InterfaceName:    "eth1",
   324  		VLANTag:          1,
   325  		MACAddress:       "aa:bb:cc:dd:ee:f1",
   326  		Disabled:         false,
   327  		NoAutoStart:      true,
   328  		ConfigType:       network.ConfigDHCP,
   329  		Address:          network.NewAddress("0.20.0.2"),
   330  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   331  		GatewayAddress:   network.NewAddress("0.20.0.1"),
   332  		ExtraConfig:      nil,
   333  	}, {
   334  		ProviderId:       "dummy-eth2",
   335  		ProviderSubnetId: "dummy-disabled",
   336  		NetworkName:      "juju-disabled",
   337  		CIDR:             "0.30.0.0/24",
   338  		DeviceIndex:      2,
   339  		InterfaceName:    "eth2",
   340  		VLANTag:          2,
   341  		MACAddress:       "aa:bb:cc:dd:ee:f2",
   342  		Disabled:         true,
   343  		NoAutoStart:      false,
   344  		ConfigType:       network.ConfigDHCP,
   345  		Address:          network.NewAddress("0.30.0.2"),
   346  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   347  		GatewayAddress:   network.NewAddress("0.30.0.1"),
   348  		ExtraConfig:      nil,
   349  	}}
   350  	info, err := e.NetworkInterfaces("i-42")
   351  	c.Assert(err, jc.ErrorIsNil)
   352  	c.Assert(info, jc.DeepEquals, expectInfo)
   353  	assertInterfaces(c, e, opc, "i-42", expectInfo)
   354  
   355  	// Test that with instance id prefix "i-no-nics-" no results are
   356  	// returned.
   357  	info, err = e.NetworkInterfaces("i-no-nics-here")
   358  	c.Assert(err, jc.ErrorIsNil)
   359  	c.Assert(info, gc.HasLen, 0)
   360  	assertInterfaces(c, e, opc, "i-no-nics-here", expectInfo[:0])
   361  
   362  	// Test that with instance id prefix "i-nic-no-subnet-" we get a result
   363  	// with no associated subnet.
   364  	expectInfo = []network.InterfaceInfo{{
   365  		DeviceIndex:   0,
   366  		ProviderId:    network.Id("dummy-eth0"),
   367  		NetworkName:   "juju-public",
   368  		InterfaceName: "eth0",
   369  		MACAddress:    "aa:bb:cc:dd:ee:f0",
   370  		Disabled:      false,
   371  		NoAutoStart:   false,
   372  		ConfigType:    network.ConfigDHCP,
   373  	}}
   374  	info, err = e.NetworkInterfaces("i-nic-no-subnet-here")
   375  	c.Assert(err, jc.ErrorIsNil)
   376  	c.Assert(info, gc.HasLen, 1)
   377  	assertInterfaces(c, e, opc, "i-nic-no-subnet-here", expectInfo)
   378  
   379  	// Test that with instance id prefix "i-disabled-nic-" we get a result
   380  	// with only a disabled subnet.
   381  	expectInfo = []network.InterfaceInfo{{
   382  		ProviderId:       "dummy-eth2",
   383  		ProviderSubnetId: "dummy-disabled",
   384  		NetworkName:      "juju-disabled",
   385  		CIDR:             "0.30.0.0/24",
   386  		DeviceIndex:      2,
   387  		InterfaceName:    "eth2",
   388  		VLANTag:          2,
   389  		MACAddress:       "aa:bb:cc:dd:ee:f2",
   390  		Disabled:         true,
   391  		NoAutoStart:      false,
   392  		ConfigType:       network.ConfigDHCP,
   393  		Address:          network.NewAddress("0.30.0.2"),
   394  		DNSServers:       network.NewAddresses("ns1.dummy", "ns2.dummy"),
   395  		GatewayAddress:   network.NewAddress("0.30.0.1"),
   396  		ExtraConfig:      nil,
   397  	}}
   398  	info, err = e.NetworkInterfaces("i-disabled-nic-here")
   399  	c.Assert(err, jc.ErrorIsNil)
   400  	c.Assert(info, gc.HasLen, 1)
   401  	assertInterfaces(c, e, opc, "i-disabled-nic-here", expectInfo)
   402  
   403  	// Test we can induce errors.
   404  	s.breakMethods(c, e, "NetworkInterfaces")
   405  	info, err = e.NetworkInterfaces("i-any")
   406  	c.Assert(err, gc.ErrorMatches, `dummy\.NetworkInterfaces is broken`)
   407  	c.Assert(info, gc.HasLen, 0)
   408  }
   409  
   410  func (s *suite) TestSubnets(c *gc.C) {
   411  	e := s.bootstrapTestEnviron(c, false)
   412  	defer func() {
   413  		err := e.Destroy()
   414  		c.Assert(err, jc.ErrorIsNil)
   415  	}()
   416  
   417  	opc := make(chan dummy.Operation, 200)
   418  	dummy.Listen(opc)
   419  
   420  	expectInfo := []network.SubnetInfo{{
   421  		CIDR:              "0.10.0.0/24",
   422  		ProviderId:        "dummy-private",
   423  		AllocatableIPLow:  net.ParseIP("0.10.0.0"),
   424  		AllocatableIPHigh: net.ParseIP("0.10.0.255"),
   425  		AvailabilityZones: []string{"zone1", "zone2"},
   426  	}, {
   427  		CIDR:              "0.20.0.0/24",
   428  		ProviderId:        "dummy-public",
   429  		AllocatableIPLow:  net.ParseIP("0.20.0.0"),
   430  		AllocatableIPHigh: net.ParseIP("0.20.0.255"),
   431  	}}
   432  	// Prepare a version of the above with no allocatable range to
   433  	// test the magic "i-no-alloc-" prefix below.
   434  	noallocInfo := make([]network.SubnetInfo, len(expectInfo))
   435  	for i, exp := range expectInfo {
   436  		pid := string(exp.ProviderId)
   437  		pid = strings.TrimPrefix(pid, "dummy-")
   438  		noallocInfo[i].ProviderId = network.Id("noalloc-" + pid)
   439  		noallocInfo[i].AllocatableIPLow = nil
   440  		noallocInfo[i].AllocatableIPHigh = nil
   441  		noallocInfo[i].AvailabilityZones = exp.AvailabilityZones
   442  		noallocInfo[i].CIDR = exp.CIDR
   443  	}
   444  
   445  	ids := []network.Id{"dummy-private", "dummy-public", "foo-bar"}
   446  	netInfo, err := e.Subnets("i-foo", ids)
   447  	c.Assert(err, jc.ErrorIsNil)
   448  	c.Assert(netInfo, jc.DeepEquals, expectInfo)
   449  	assertSubnets(c, e, opc, "i-foo", ids, expectInfo)
   450  
   451  	// Test filtering by id(s).
   452  	netInfo, err = e.Subnets("i-foo", nil)
   453  	c.Assert(err, jc.ErrorIsNil)
   454  	c.Assert(netInfo, jc.DeepEquals, expectInfo)
   455  	assertSubnets(c, e, opc, "i-foo", nil, expectInfo)
   456  	netInfo, err = e.Subnets("i-foo", ids[0:1])
   457  	c.Assert(err, jc.ErrorIsNil)
   458  	c.Assert(netInfo, jc.DeepEquals, expectInfo[0:1])
   459  	assertSubnets(c, e, opc, "i-foo", ids[0:1], expectInfo[0:1])
   460  	netInfo, err = e.Subnets("i-foo", ids[1:])
   461  	c.Assert(err, jc.ErrorIsNil)
   462  	c.Assert(netInfo, jc.DeepEquals, expectInfo[1:])
   463  	assertSubnets(c, e, opc, "i-foo", ids[1:], expectInfo[1:])
   464  
   465  	// Test that using an instance id with prefix of either
   466  	// "i-no-subnets-" or "i-nic-no-subnet-"
   467  	// returns no results, regardless whether ids are given or not.
   468  	for _, instId := range []instance.Id{"i-no-subnets-foo", "i-nic-no-subnet-foo"} {
   469  		netInfo, err = e.Subnets(instId, nil)
   470  		c.Assert(err, jc.ErrorIsNil)
   471  		c.Assert(netInfo, gc.HasLen, 0)
   472  		assertSubnets(c, e, opc, instId, nil, expectInfo[:0])
   473  	}
   474  
   475  	netInfo, err = e.Subnets("i-no-subnets-foo", ids)
   476  	c.Assert(err, jc.ErrorIsNil)
   477  	c.Assert(netInfo, gc.HasLen, 0)
   478  	assertSubnets(c, e, opc, "i-no-subnets-foo", ids, expectInfo[:0])
   479  
   480  	// Test the behavior with "i-no-alloc-" instance id prefix.
   481  	// When # is "all", all returned subnets have no allocatable range
   482  	// set and have provider ids with "noalloc-" prefix.
   483  	netInfo, err = e.Subnets("i-no-alloc-all", nil)
   484  	c.Assert(err, jc.ErrorIsNil)
   485  	c.Assert(netInfo, jc.DeepEquals, noallocInfo)
   486  	assertSubnets(c, e, opc, "i-no-alloc-all", nil, noallocInfo)
   487  
   488  	// When # is an integer, the #-th subnet in result has no
   489  	// allocatable range set and a provider id prefix "noalloc-".
   490  	netInfo, err = e.Subnets("i-no-alloc-0", nil)
   491  	c.Assert(err, jc.ErrorIsNil)
   492  	expectResult := []network.SubnetInfo{noallocInfo[0], expectInfo[1]}
   493  	c.Assert(netInfo, jc.DeepEquals, expectResult)
   494  	assertSubnets(c, e, opc, "i-no-alloc-0", nil, expectResult)
   495  
   496  	netInfo, err = e.Subnets("i-no-alloc-1", nil)
   497  	c.Assert(err, jc.ErrorIsNil)
   498  	expectResult = []network.SubnetInfo{expectInfo[0], noallocInfo[1]}
   499  	c.Assert(netInfo, jc.DeepEquals, expectResult)
   500  	assertSubnets(c, e, opc, "i-no-alloc-1", nil, expectResult)
   501  
   502  	// For the last case above, also test the error returned when # is
   503  	// not integer or it's out of range of the results (including when
   504  	// filtering by ids is applied).
   505  	netInfo, err = e.Subnets("i-no-alloc-foo", nil)
   506  	c.Assert(err, gc.ErrorMatches, `invalid index "foo"; expected int`)
   507  	c.Assert(netInfo, gc.HasLen, 0)
   508  
   509  	netInfo, err = e.Subnets("i-no-alloc-1", ids[:1])
   510  	c.Assert(err, gc.ErrorMatches, `index 1 out of range; expected 0..0`)
   511  	c.Assert(netInfo, gc.HasLen, 0)
   512  
   513  	netInfo, err = e.Subnets("i-no-alloc-2", ids)
   514  	c.Assert(err, gc.ErrorMatches, `index 2 out of range; expected 0..1`)
   515  	c.Assert(netInfo, gc.HasLen, 0)
   516  
   517  	// Test we can induce errors.
   518  	s.breakMethods(c, e, "Subnets")
   519  	netInfo, err = e.Subnets("i-any", nil)
   520  	c.Assert(err, gc.ErrorMatches, `dummy\.Subnets is broken`)
   521  	c.Assert(netInfo, gc.HasLen, 0)
   522  }
   523  
   524  func (s *suite) TestPreferIPv6On(c *gc.C) {
   525  	e := s.bootstrapTestEnviron(c, true)
   526  	defer func() {
   527  		err := e.Destroy()
   528  		c.Assert(err, jc.ErrorIsNil)
   529  	}()
   530  
   531  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   532  	c.Assert(inst, gc.NotNil)
   533  	addrs, err := inst.Addresses()
   534  	c.Assert(err, jc.ErrorIsNil)
   535  	c.Assert(addrs, jc.DeepEquals, network.NewAddresses("only-0.dns", "127.0.0.1", "fc00::1"))
   536  }
   537  
   538  func (s *suite) TestPreferIPv6Off(c *gc.C) {
   539  	e := s.bootstrapTestEnviron(c, false)
   540  	defer func() {
   541  		err := e.Destroy()
   542  		c.Assert(err, jc.ErrorIsNil)
   543  	}()
   544  
   545  	inst, _ := jujutesting.AssertStartInstance(c, e, "0")
   546  	c.Assert(inst, gc.NotNil)
   547  	addrs, err := inst.Addresses()
   548  	c.Assert(err, jc.ErrorIsNil)
   549  	c.Assert(addrs, jc.DeepEquals, network.NewAddresses("only-0.dns", "127.0.0.1"))
   550  }
   551  
   552  func assertAllocateAddress(c *gc.C, e environs.Environ, opc chan dummy.Operation, expectInstId instance.Id, expectSubnetId network.Id, expectAddress network.Address, expectMAC, expectHostName string) {
   553  	select {
   554  	case op := <-opc:
   555  		addrOp, ok := op.(dummy.OpAllocateAddress)
   556  		if !ok {
   557  			c.Fatalf("unexpected op: %#v", op)
   558  		}
   559  		c.Check(addrOp.SubnetId, gc.Equals, expectSubnetId)
   560  		c.Check(addrOp.InstanceId, gc.Equals, expectInstId)
   561  		c.Check(addrOp.Address, gc.Equals, expectAddress)
   562  		c.Check(addrOp.MACAddress, gc.Equals, expectMAC)
   563  		c.Check(addrOp.HostName, gc.Equals, expectHostName)
   564  		return
   565  	case <-time.After(testing.ShortWait):
   566  		c.Fatalf("time out wating for operation")
   567  	}
   568  }
   569  
   570  func assertReleaseAddress(c *gc.C, e environs.Environ, opc chan dummy.Operation, expectInstId instance.Id, expectSubnetId network.Id, expectAddress network.Address, macAddress string) {
   571  	select {
   572  	case op := <-opc:
   573  		addrOp, ok := op.(dummy.OpReleaseAddress)
   574  		if !ok {
   575  			c.Fatalf("unexpected op: %#v", op)
   576  		}
   577  		c.Check(addrOp.SubnetId, gc.Equals, expectSubnetId)
   578  		c.Check(addrOp.InstanceId, gc.Equals, expectInstId)
   579  		c.Check(addrOp.Address, gc.Equals, expectAddress)
   580  		c.Check(addrOp.MACAddress, gc.Equals, macAddress)
   581  		return
   582  	case <-time.After(testing.ShortWait):
   583  		c.Fatalf("time out wating for operation")
   584  	}
   585  }
   586  
   587  func assertInterfaces(c *gc.C, e environs.Environ, opc chan dummy.Operation, expectInstId instance.Id, expectInfo []network.InterfaceInfo) {
   588  	select {
   589  	case op := <-opc:
   590  		netOp, ok := op.(dummy.OpNetworkInterfaces)
   591  		if !ok {
   592  			c.Fatalf("unexpected op: %#v", op)
   593  		}
   594  		c.Check(netOp.Env, gc.Equals, e.Config().Name())
   595  		c.Check(netOp.InstanceId, gc.Equals, expectInstId)
   596  		c.Check(netOp.Info, jc.DeepEquals, expectInfo)
   597  		return
   598  	case <-time.After(testing.ShortWait):
   599  		c.Fatalf("time out wating for operation")
   600  	}
   601  }
   602  
   603  func assertSubnets(
   604  	c *gc.C,
   605  	e environs.Environ,
   606  	opc chan dummy.Operation,
   607  	instId instance.Id,
   608  	subnetIds []network.Id,
   609  	expectInfo []network.SubnetInfo,
   610  ) {
   611  	select {
   612  	case op := <-opc:
   613  		netOp, ok := op.(dummy.OpSubnets)
   614  		if !ok {
   615  			c.Fatalf("unexpected op: %#v", op)
   616  		}
   617  		c.Check(netOp.InstanceId, gc.Equals, instId)
   618  		c.Check(netOp.SubnetIds, jc.DeepEquals, subnetIds)
   619  		c.Check(netOp.Info, jc.DeepEquals, expectInfo)
   620  		return
   621  	case <-time.After(testing.ShortWait):
   622  		c.Fatalf("time out wating for operation")
   623  	}
   624  }