github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/testing/stub_network.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  
    11  	"github.com/juju/juju/apiserver/common/networkingcommon"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/environs"
    14  	"github.com/juju/juju/environs/config"
    15  	"github.com/juju/juju/instance"
    16  	"github.com/juju/juju/network"
    17  	providercommon "github.com/juju/juju/provider/common"
    18  	coretesting "github.com/juju/juju/testing"
    19  	"github.com/juju/testing"
    20  	"github.com/juju/utils"
    21  	"github.com/juju/utils/set"
    22  	gc "gopkg.in/check.v1"
    23  	names "gopkg.in/juju/names.v2"
    24  )
    25  
    26  type StubNetwork struct {
    27  }
    28  
    29  var (
    30  	// SharedStub records all method calls to any of the stubs.
    31  	SharedStub = &testing.Stub{}
    32  
    33  	BackingInstance                = &StubBacking{Stub: SharedStub}
    34  	ProviderInstance               = &StubProvider{Stub: SharedStub}
    35  	EnvironInstance                = &StubEnviron{Stub: SharedStub}
    36  	ZonedEnvironInstance           = &StubZonedEnviron{Stub: SharedStub}
    37  	NetworkingEnvironInstance      = &StubNetworkingEnviron{Stub: SharedStub}
    38  	ZonedNetworkingEnvironInstance = &StubZonedNetworkingEnviron{Stub: SharedStub}
    39  )
    40  
    41  const (
    42  	StubProviderType               = "stub-provider"
    43  	StubEnvironName                = "stub-environ"
    44  	StubZonedEnvironName           = "stub-zoned-environ"
    45  	StubNetworkingEnvironName      = "stub-networking-environ"
    46  	StubZonedNetworkingEnvironName = "stub-zoned-networking-environ"
    47  )
    48  
    49  func (s StubNetwork) SetUpSuite(c *gc.C) {
    50  	providers := environs.RegisteredProviders()
    51  	for _, name := range providers {
    52  		if name == StubProviderType {
    53  			return
    54  		}
    55  	}
    56  
    57  	ProviderInstance.Zones = []providercommon.AvailabilityZone{
    58  		&FakeZone{"zone1", true},
    59  		&FakeZone{"zone2", false},
    60  		&FakeZone{"zone3", true},
    61  		&FakeZone{"zone4", false},
    62  		&FakeZone{"zone4", false}, // duplicates are ignored
    63  	}
    64  	ProviderInstance.Subnets = []network.SubnetInfo{{
    65  		CIDR:              "10.10.0.0/24",
    66  		ProviderId:        "sn-zadf00d",
    67  		AvailabilityZones: []string{"zone1"},
    68  	}, {
    69  		CIDR:              "2001:db8::/32",
    70  		ProviderId:        "sn-ipv6",
    71  		AvailabilityZones: []string{"zone1", "zone3"},
    72  	}, {
    73  		// no CIDR or provider id -> cached, but cannot be added
    74  		CIDR:       "",
    75  		ProviderId: "",
    76  	}, {
    77  		// no CIDR, just provider id -> cached, but can only be added by id
    78  		CIDR:       "",
    79  		ProviderId: "sn-empty",
    80  	}, {
    81  		// invalid CIDR and provider id -> cannot be added, but is cached
    82  		CIDR:       "invalid",
    83  		ProviderId: "sn-invalid",
    84  	}, {
    85  		// incorrectly specified CIDR, with provider id -> cached, cannot be added
    86  		CIDR:       "0.1.2.3/4",
    87  		ProviderId: "sn-awesome",
    88  	}, {
    89  		// no zones, no provider-id -> cached, but can only be added by CIDR
    90  		CIDR: "10.20.0.0/16",
    91  	}, {
    92  		// with zones, duplicate provider-id -> overwritten by the last
    93  		// subnet with the same provider id when caching.
    94  		CIDR:              "10.99.88.0/24",
    95  		ProviderId:        "sn-deadbeef",
    96  		AvailabilityZones: []string{"zone1", "zone2"},
    97  	}, {
    98  		// no zones
    99  		CIDR:       "10.42.0.0/16",
   100  		ProviderId: "sn-42",
   101  	}, {
   102  		// in an unavailable zone, duplicate CIDR -> cannot be added, but is cached
   103  		CIDR:              "10.10.0.0/24",
   104  		ProviderId:        "sn-deadbeef",
   105  		AvailabilityZones: []string{"zone2"},
   106  	}, {
   107  		CIDR:              "10.30.1.0/24",
   108  		ProviderId:        "vlan-42",
   109  		VLANTag:           42,
   110  		AvailabilityZones: []string{"zone3"},
   111  	}}
   112  
   113  	environs.RegisterProvider(StubProviderType, ProviderInstance)
   114  }
   115  
   116  type errReturner func() error
   117  
   118  // FakeSpace implements networkingcommon.BackingSpace for testing.
   119  type FakeSpace struct {
   120  	SpaceName string
   121  	SubnetIds []string
   122  	Public    bool
   123  	NextErr   errReturner
   124  }
   125  
   126  var _ networkingcommon.BackingSpace = (*FakeSpace)(nil)
   127  
   128  func (f *FakeSpace) Name() string {
   129  	return f.SpaceName
   130  }
   131  
   132  func (f *FakeSpace) Subnets() (bs []networkingcommon.BackingSubnet, err error) {
   133  	outputSubnets := []networkingcommon.BackingSubnet{}
   134  
   135  	if err = f.NextErr(); err != nil {
   136  		return outputSubnets, err
   137  	}
   138  
   139  	for _, subnetId := range f.SubnetIds {
   140  		providerId := network.Id("provider-" + subnetId)
   141  
   142  		// Pick the third element of the IP address and use this to
   143  		// decide how we construct the Subnet. It provides variation of
   144  		// test data.
   145  		first, err := strconv.Atoi(strings.Split(subnetId, ".")[2])
   146  		if err != nil {
   147  			return outputSubnets, err
   148  		}
   149  		vlantag := 0
   150  		zones := []string{"foo"}
   151  		status := "in-use"
   152  		if first%2 == 1 {
   153  			vlantag = 23
   154  			zones = []string{"bar", "bam"}
   155  			status = ""
   156  		}
   157  
   158  		backing := networkingcommon.BackingSubnetInfo{
   159  			CIDR:              subnetId,
   160  			SpaceName:         f.SpaceName,
   161  			ProviderId:        providerId,
   162  			VLANTag:           vlantag,
   163  			AvailabilityZones: zones,
   164  			Status:            status,
   165  		}
   166  		outputSubnets = append(outputSubnets, &FakeSubnet{info: backing})
   167  	}
   168  
   169  	return outputSubnets, nil
   170  }
   171  
   172  func (f *FakeSpace) ProviderId() (netID network.Id) {
   173  	return
   174  }
   175  
   176  func (f *FakeSpace) Zones() []string {
   177  	return []string{""}
   178  }
   179  
   180  func (f *FakeSpace) Life() (life params.Life) {
   181  	return
   182  }
   183  
   184  // GoString implements fmt.GoStringer.
   185  func (f *FakeSpace) GoString() string {
   186  	return fmt.Sprintf("&FakeSpace{%q}", f.SpaceName)
   187  }
   188  
   189  // StubMethodCall is like testing.StubCall, but includes the receiver
   190  // as well.
   191  type StubMethodCall struct {
   192  	Receiver interface{}
   193  	FuncName string
   194  	Args     []interface{}
   195  }
   196  
   197  // BackingCall makes it easy to check method calls on BackingInstance.
   198  func BackingCall(name string, args ...interface{}) StubMethodCall {
   199  	return StubMethodCall{
   200  		Receiver: BackingInstance,
   201  		FuncName: name,
   202  		Args:     args,
   203  	}
   204  }
   205  
   206  // ProviderCall makes it easy to check method calls on ProviderInstance.
   207  func ProviderCall(name string, args ...interface{}) StubMethodCall {
   208  	return StubMethodCall{
   209  		Receiver: ProviderInstance,
   210  		FuncName: name,
   211  		Args:     args,
   212  	}
   213  }
   214  
   215  // EnvironCall makes it easy to check method calls on EnvironInstance.
   216  func EnvironCall(name string, args ...interface{}) StubMethodCall {
   217  	return StubMethodCall{
   218  		Receiver: EnvironInstance,
   219  		FuncName: name,
   220  		Args:     args,
   221  	}
   222  }
   223  
   224  // ZonedEnvironCall makes it easy to check method calls on
   225  // ZonedEnvironInstance.
   226  func ZonedEnvironCall(name string, args ...interface{}) StubMethodCall {
   227  	return StubMethodCall{
   228  		Receiver: ZonedEnvironInstance,
   229  		FuncName: name,
   230  		Args:     args,
   231  	}
   232  }
   233  
   234  // NetworkingEnvironCall makes it easy to check method calls on
   235  // NetworkingEnvironInstance.
   236  func NetworkingEnvironCall(name string, args ...interface{}) StubMethodCall {
   237  	return StubMethodCall{
   238  		Receiver: NetworkingEnvironInstance,
   239  		FuncName: name,
   240  		Args:     args,
   241  	}
   242  }
   243  
   244  // ZonedNetworkingEnvironCall makes it easy to check method calls on
   245  // ZonedNetworkingEnvironInstance.
   246  func ZonedNetworkingEnvironCall(name string, args ...interface{}) StubMethodCall {
   247  	return StubMethodCall{
   248  		Receiver: ZonedNetworkingEnvironInstance,
   249  		FuncName: name,
   250  		Args:     args,
   251  	}
   252  }
   253  
   254  // CheckMethodCalls works like testing.Stub.CheckCalls, but also
   255  // checks the receivers.
   256  func CheckMethodCalls(c *gc.C, stub *testing.Stub, calls ...StubMethodCall) {
   257  	receivers := make([]interface{}, len(calls))
   258  	for i, call := range calls {
   259  		receivers[i] = call.Receiver
   260  	}
   261  	stub.CheckReceivers(c, receivers...)
   262  	c.Check(stub.Calls(), gc.HasLen, len(calls))
   263  	for i, call := range calls {
   264  		stub.CheckCall(c, i, call.FuncName, call.Args...)
   265  	}
   266  }
   267  
   268  // FakeZone implements providercommon.AvailabilityZone for testing.
   269  type FakeZone struct {
   270  	ZoneName      string
   271  	ZoneAvailable bool
   272  }
   273  
   274  var _ providercommon.AvailabilityZone = (*FakeZone)(nil)
   275  
   276  func (f *FakeZone) Name() string {
   277  	return f.ZoneName
   278  }
   279  
   280  func (f *FakeZone) Available() bool {
   281  	return f.ZoneAvailable
   282  }
   283  
   284  // GoString implements fmt.GoStringer.
   285  func (f *FakeZone) GoString() string {
   286  	return fmt.Sprintf("&FakeZone{%q, %v}", f.ZoneName, f.ZoneAvailable)
   287  }
   288  
   289  // FakeSubnet implements networkingcommon.BackingSubnet for testing.
   290  type FakeSubnet struct {
   291  	info networkingcommon.BackingSubnetInfo
   292  }
   293  
   294  var _ networkingcommon.BackingSubnet = (*FakeSubnet)(nil)
   295  
   296  // GoString implements fmt.GoStringer.
   297  func (f *FakeSubnet) GoString() string {
   298  	return fmt.Sprintf("&FakeSubnet{%#v}", f.info)
   299  }
   300  
   301  func (f *FakeSubnet) Status() string {
   302  	return f.info.Status
   303  }
   304  
   305  func (f *FakeSubnet) CIDR() string {
   306  	return f.info.CIDR
   307  }
   308  
   309  func (f *FakeSubnet) AvailabilityZones() []string {
   310  	return f.info.AvailabilityZones
   311  }
   312  
   313  func (f *FakeSubnet) ProviderId() network.Id {
   314  	return f.info.ProviderId
   315  }
   316  
   317  func (f *FakeSubnet) VLANTag() int {
   318  	return f.info.VLANTag
   319  }
   320  
   321  func (f *FakeSubnet) SpaceName() string {
   322  	return f.info.SpaceName
   323  }
   324  
   325  func (f *FakeSubnet) Life() params.Life {
   326  	return f.info.Life
   327  }
   328  
   329  // ResetStub resets all recorded calls and errors of the given stub.
   330  func ResetStub(stub *testing.Stub) {
   331  	*stub = testing.Stub{}
   332  }
   333  
   334  // StubBacking implements networkingcommon.NetworkBacking and records calls to its
   335  // methods.
   336  type StubBacking struct {
   337  	*testing.Stub
   338  
   339  	EnvConfig *config.Config
   340  	Cloud     environs.CloudSpec
   341  
   342  	Zones   []providercommon.AvailabilityZone
   343  	Spaces  []networkingcommon.BackingSpace
   344  	Subnets []networkingcommon.BackingSubnet
   345  }
   346  
   347  var _ networkingcommon.NetworkBacking = (*StubBacking)(nil)
   348  
   349  type SetUpFlag bool
   350  
   351  const (
   352  	WithZones      SetUpFlag = true
   353  	WithoutZones   SetUpFlag = false
   354  	WithSpaces     SetUpFlag = true
   355  	WithoutSpaces  SetUpFlag = false
   356  	WithSubnets    SetUpFlag = true
   357  	WithoutSubnets SetUpFlag = false
   358  )
   359  
   360  func (sb *StubBacking) SetUp(c *gc.C, envName string, withZones, withSpaces, withSubnets SetUpFlag) {
   361  	// This method must be called at the beginning of each test, which
   362  	// needs access to any of the mocks, to reset the recorded calls
   363  	// and errors, as well as to initialize the mocks as needed.
   364  	ResetStub(sb.Stub)
   365  
   366  	// Make sure we use the stub provider.
   367  	extraAttrs := coretesting.Attrs{
   368  		"uuid": utils.MustNewUUID().String(),
   369  		"type": StubProviderType,
   370  		"name": envName,
   371  	}
   372  	sb.EnvConfig = coretesting.CustomModelConfig(c, extraAttrs)
   373  	sb.Cloud = environs.CloudSpec{
   374  		Type:             StubProviderType,
   375  		Name:             "cloud-name",
   376  		Endpoint:         "endpoint",
   377  		IdentityEndpoint: "identity-endpoint",
   378  		StorageEndpoint:  "storage-endpoint",
   379  	}
   380  	sb.Zones = []providercommon.AvailabilityZone{}
   381  	if withZones {
   382  		sb.Zones = make([]providercommon.AvailabilityZone, len(ProviderInstance.Zones))
   383  		copy(sb.Zones, ProviderInstance.Zones)
   384  	}
   385  	sb.Spaces = []networkingcommon.BackingSpace{}
   386  	if withSpaces {
   387  		// Note that full subnet data is generated from the SubnetIds in
   388  		// FakeSpace.Subnets().
   389  		sb.Spaces = []networkingcommon.BackingSpace{
   390  			&FakeSpace{
   391  				SpaceName: "default",
   392  				SubnetIds: []string{"192.168.0.0/24", "192.168.3.0/24"},
   393  				NextErr:   sb.NextErr},
   394  			&FakeSpace{
   395  				SpaceName: "dmz",
   396  				SubnetIds: []string{"192.168.1.0/24"},
   397  				NextErr:   sb.NextErr},
   398  			&FakeSpace{
   399  				SpaceName: "private",
   400  				SubnetIds: []string{"192.168.2.0/24"},
   401  				NextErr:   sb.NextErr},
   402  			&FakeSpace{
   403  				SpaceName: "private",
   404  				SubnetIds: []string{"192.168.2.0/24"},
   405  				NextErr:   sb.NextErr}, // duplicates are ignored when caching spaces.
   406  		}
   407  	}
   408  	sb.Subnets = []networkingcommon.BackingSubnet{}
   409  	if withSubnets {
   410  		info0 := networkingcommon.BackingSubnetInfo{
   411  			CIDR:              ProviderInstance.Subnets[0].CIDR,
   412  			ProviderId:        ProviderInstance.Subnets[0].ProviderId,
   413  			AvailabilityZones: ProviderInstance.Subnets[0].AvailabilityZones,
   414  			SpaceName:         "private",
   415  		}
   416  		info1 := networkingcommon.BackingSubnetInfo{
   417  			CIDR:              ProviderInstance.Subnets[1].CIDR,
   418  			ProviderId:        ProviderInstance.Subnets[1].ProviderId,
   419  			AvailabilityZones: ProviderInstance.Subnets[1].AvailabilityZones,
   420  			SpaceName:         "dmz",
   421  		}
   422  
   423  		sb.Subnets = []networkingcommon.BackingSubnet{
   424  			&FakeSubnet{info0},
   425  			&FakeSubnet{info1},
   426  		}
   427  	}
   428  }
   429  
   430  func (sb *StubBacking) ModelConfig() (*config.Config, error) {
   431  	sb.MethodCall(sb, "ModelConfig")
   432  	if err := sb.NextErr(); err != nil {
   433  		return nil, err
   434  	}
   435  	return sb.EnvConfig, nil
   436  }
   437  
   438  func (sb *StubBacking) ModelTag() names.ModelTag {
   439  	return names.NewModelTag("dbeef-2f18-4fd2-967d-db9663db7bea")
   440  }
   441  
   442  func (sb *StubBacking) CloudSpec(names.ModelTag) (environs.CloudSpec, error) {
   443  	sb.MethodCall(sb, "CloudSpec")
   444  	if err := sb.NextErr(); err != nil {
   445  		return environs.CloudSpec{}, err
   446  	}
   447  	return sb.Cloud, nil
   448  }
   449  
   450  func (sb *StubBacking) AvailabilityZones() ([]providercommon.AvailabilityZone, error) {
   451  	sb.MethodCall(sb, "AvailabilityZones")
   452  	if err := sb.NextErr(); err != nil {
   453  		return nil, err
   454  	}
   455  	return sb.Zones, nil
   456  }
   457  
   458  func (sb *StubBacking) SetAvailabilityZones(zones []providercommon.AvailabilityZone) error {
   459  	sb.MethodCall(sb, "SetAvailabilityZones", zones)
   460  	return sb.NextErr()
   461  }
   462  
   463  func (sb *StubBacking) AllSpaces() ([]networkingcommon.BackingSpace, error) {
   464  	sb.MethodCall(sb, "AllSpaces")
   465  	if err := sb.NextErr(); err != nil {
   466  		return nil, err
   467  	}
   468  
   469  	// Filter duplicates.
   470  	seen := set.Strings{}
   471  	output := []networkingcommon.BackingSpace{}
   472  	for _, space := range sb.Spaces {
   473  		if seen.Contains(space.Name()) {
   474  			continue
   475  		}
   476  		seen.Add(space.Name())
   477  		output = append(output, space)
   478  	}
   479  	return output, nil
   480  }
   481  
   482  func (sb *StubBacking) AllSubnets() ([]networkingcommon.BackingSubnet, error) {
   483  	sb.MethodCall(sb, "AllSubnets")
   484  	if err := sb.NextErr(); err != nil {
   485  		return nil, err
   486  	}
   487  
   488  	// Filter duplicates.
   489  	seen := set.Strings{}
   490  	output := []networkingcommon.BackingSubnet{}
   491  	for _, subnet := range sb.Subnets {
   492  		if seen.Contains(subnet.CIDR()) {
   493  			continue
   494  		}
   495  		seen.Add(subnet.CIDR())
   496  		output = append(output, subnet)
   497  	}
   498  	return output, nil
   499  }
   500  
   501  func (sb *StubBacking) AddSubnet(subnetInfo networkingcommon.BackingSubnetInfo) (networkingcommon.BackingSubnet, error) {
   502  	sb.MethodCall(sb, "AddSubnet", subnetInfo)
   503  	if err := sb.NextErr(); err != nil {
   504  		return nil, err
   505  	}
   506  	fs := &FakeSubnet{info: subnetInfo}
   507  	sb.Subnets = append(sb.Subnets, fs)
   508  	return fs, nil
   509  }
   510  
   511  func (sb *StubBacking) AddSpace(name string, providerId network.Id, subnets []string, public bool) error {
   512  	sb.MethodCall(sb, "AddSpace", name, providerId, subnets, public)
   513  	if err := sb.NextErr(); err != nil {
   514  		return err
   515  	}
   516  	fs := &FakeSpace{SpaceName: name, SubnetIds: subnets, Public: public}
   517  	sb.Spaces = append(sb.Spaces, fs)
   518  	return nil
   519  }
   520  
   521  // GoString implements fmt.GoStringer.
   522  func (se *StubBacking) GoString() string {
   523  	return "&StubBacking{}"
   524  }
   525  
   526  // StubProvider implements a subset of environs.EnvironProvider
   527  // methods used in tests.
   528  type StubProvider struct {
   529  	*testing.Stub
   530  
   531  	Zones   []providercommon.AvailabilityZone
   532  	Subnets []network.SubnetInfo
   533  
   534  	environs.EnvironProvider // panic on any not implemented method call.
   535  }
   536  
   537  var _ environs.EnvironProvider = (*StubProvider)(nil)
   538  
   539  func (sp *StubProvider) Open(args environs.OpenParams) (environs.Environ, error) {
   540  	sp.MethodCall(sp, "Open", args.Config)
   541  	if err := sp.NextErr(); err != nil {
   542  		return nil, err
   543  	}
   544  	switch args.Config.Name() {
   545  	case StubEnvironName:
   546  		return EnvironInstance, nil
   547  	case StubZonedEnvironName:
   548  		return ZonedEnvironInstance, nil
   549  	case StubNetworkingEnvironName:
   550  		return NetworkingEnvironInstance, nil
   551  	case StubZonedNetworkingEnvironName:
   552  		return ZonedNetworkingEnvironInstance, nil
   553  	}
   554  	panic("unexpected model name: " + args.Config.Name())
   555  }
   556  
   557  // GoString implements fmt.GoStringer.
   558  func (se *StubProvider) GoString() string {
   559  	return "&StubProvider{}"
   560  }
   561  
   562  // StubEnviron is used in tests where environs.Environ is needed.
   563  type StubEnviron struct {
   564  	*testing.Stub
   565  
   566  	environs.Environ // panic on any not implemented method call
   567  }
   568  
   569  var _ environs.Environ = (*StubEnviron)(nil)
   570  
   571  // GoString implements fmt.GoStringer.
   572  func (se *StubEnviron) GoString() string {
   573  	return "&StubEnviron{}"
   574  }
   575  
   576  // StubZonedEnviron is used in tests where providercommon.ZonedEnviron
   577  // is needed.
   578  type StubZonedEnviron struct {
   579  	*testing.Stub
   580  
   581  	providercommon.ZonedEnviron // panic on any not implemented method call
   582  }
   583  
   584  var _ providercommon.ZonedEnviron = (*StubZonedEnviron)(nil)
   585  
   586  func (se *StubZonedEnviron) AvailabilityZones() ([]providercommon.AvailabilityZone, error) {
   587  	se.MethodCall(se, "AvailabilityZones")
   588  	if err := se.NextErr(); err != nil {
   589  		return nil, err
   590  	}
   591  	return ProviderInstance.Zones, nil
   592  }
   593  
   594  // GoString implements fmt.GoStringer.
   595  func (se *StubZonedEnviron) GoString() string {
   596  	return "&StubZonedEnviron{}"
   597  }
   598  
   599  // StubNetworkingEnviron is used in tests where
   600  // environs.NetworkingEnviron is needed.
   601  type StubNetworkingEnviron struct {
   602  	*testing.Stub
   603  
   604  	environs.NetworkingEnviron // panic on any not implemented method call
   605  }
   606  
   607  var _ environs.NetworkingEnviron = (*StubNetworkingEnviron)(nil)
   608  
   609  func (se *StubNetworkingEnviron) Subnets(instId instance.Id, subIds []network.Id) ([]network.SubnetInfo, error) {
   610  	se.MethodCall(se, "Subnets", instId, subIds)
   611  	if err := se.NextErr(); err != nil {
   612  		return nil, err
   613  	}
   614  	return ProviderInstance.Subnets, nil
   615  }
   616  
   617  func (se *StubNetworkingEnviron) SupportsSpaces() (bool, error) {
   618  	se.MethodCall(se, "SupportsSpaces")
   619  	if err := se.NextErr(); err != nil {
   620  		return false, err
   621  	}
   622  	return true, nil
   623  }
   624  
   625  // GoString implements fmt.GoStringer.
   626  func (se *StubNetworkingEnviron) GoString() string {
   627  	return "&StubNetworkingEnviron{}"
   628  }
   629  
   630  // StubZonedNetworkingEnviron is used in tests where features from
   631  // both environs.Networking and providercommon.ZonedEnviron are
   632  // needed.
   633  type StubZonedNetworkingEnviron struct {
   634  	*testing.Stub
   635  
   636  	// panic on any not implemented method call
   637  	providercommon.ZonedEnviron
   638  	environs.Networking
   639  }
   640  
   641  // GoString implements fmt.GoStringer.
   642  func (se *StubZonedNetworkingEnviron) GoString() string {
   643  	return "&StubZonedNetworkingEnviron{}"
   644  }
   645  
   646  func (se *StubZonedNetworkingEnviron) SupportsSpaces() (bool, error) {
   647  	se.MethodCall(se, "SupportsSpaces")
   648  	if err := se.NextErr(); err != nil {
   649  		return false, err
   650  	}
   651  	return true, nil
   652  }
   653  
   654  func (se *StubZonedNetworkingEnviron) Subnets(instId instance.Id, subIds []network.Id) ([]network.SubnetInfo, error) {
   655  	se.MethodCall(se, "Subnets", instId, subIds)
   656  	if err := se.NextErr(); err != nil {
   657  		return nil, err
   658  	}
   659  	return ProviderInstance.Subnets, nil
   660  }
   661  
   662  func (se *StubZonedNetworkingEnviron) AvailabilityZones() ([]providercommon.AvailabilityZone, error) {
   663  	se.MethodCall(se, "AvailabilityZones")
   664  	if err := se.NextErr(); err != nil {
   665  		return nil, err
   666  	}
   667  	return ProviderInstance.Zones, nil
   668  }