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