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