github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/provider/lxd/provider_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lxd_test
     5  
     6  import (
     7  	"net/http"
     8  	"net/http/httptest"
     9  
    10  	"github.com/golang/mock/gomock"
    11  	"github.com/juju/errors"
    12  	gitjujutesting "github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	"github.com/juju/utils"
    15  	gc "gopkg.in/check.v1"
    16  	"gopkg.in/yaml.v2"
    17  
    18  	"github.com/juju/juju/cloud"
    19  	"github.com/juju/juju/environs"
    20  	"github.com/juju/juju/environs/context"
    21  	"github.com/juju/juju/environs/testing"
    22  	"github.com/juju/juju/provider/lxd"
    23  	"github.com/juju/juju/provider/lxd/lxdnames"
    24  	jujutesting "github.com/juju/juju/testing"
    25  )
    26  
    27  var (
    28  	_ = gc.Suite(&providerSuite{})
    29  	_ = gc.Suite(&ProviderFunctionalSuite{})
    30  )
    31  
    32  type providerSuite struct {
    33  	lxd.BaseSuite
    34  
    35  	provider environs.EnvironProvider
    36  }
    37  
    38  func (s *providerSuite) SetUpTest(c *gc.C) {
    39  	s.BaseSuite.SetUpTest(c)
    40  }
    41  
    42  type providerSuiteDeps struct {
    43  	provider      environs.EnvironProvider
    44  	creds         *testing.MockProviderCredentials
    45  	credsRegister *testing.MockProviderCredentialsRegister
    46  	factory       *lxd.MockServerFactory
    47  	configReader  *lxd.MockLXCConfigReader
    48  }
    49  
    50  func (s *providerSuite) createProvider(ctrl *gomock.Controller) providerSuiteDeps {
    51  	creds := testing.NewMockProviderCredentials(ctrl)
    52  	credsRegister := testing.NewMockProviderCredentialsRegister(ctrl)
    53  	factory := lxd.NewMockServerFactory(ctrl)
    54  	configReader := lxd.NewMockLXCConfigReader(ctrl)
    55  
    56  	provider := lxd.NewProviderWithMocks(creds, credsRegister, factory, configReader)
    57  	return providerSuiteDeps{
    58  		provider:      provider,
    59  		creds:         creds,
    60  		credsRegister: credsRegister,
    61  		factory:       factory,
    62  		configReader:  configReader,
    63  	}
    64  }
    65  
    66  func (s *providerSuite) TestDetectClouds(c *gc.C) {
    67  	ctrl := gomock.NewController(c)
    68  	defer ctrl.Finish()
    69  
    70  	deps := s.createProvider(ctrl)
    71  	deps.configReader.EXPECT().ReadConfig(".config/lxc/config.yml").Return(lxd.LXCConfig{}, nil)
    72  
    73  	cloudDetector := deps.provider.(environs.CloudDetector)
    74  
    75  	clouds, err := cloudDetector.DetectClouds()
    76  	c.Assert(err, jc.ErrorIsNil)
    77  	c.Assert(clouds, gc.HasLen, 1)
    78  	s.assertLocalhostCloud(c, clouds[0])
    79  }
    80  
    81  func (s *providerSuite) TestRemoteDetectClouds(c *gc.C) {
    82  	ctrl := gomock.NewController(c)
    83  	defer ctrl.Finish()
    84  
    85  	deps := s.createProvider(ctrl)
    86  	deps.configReader.EXPECT().ReadConfig(".config/lxc/config.yml").Return(lxd.LXCConfig{
    87  		DefaultRemote: "localhost",
    88  		Remotes: map[string]lxd.LXCRemoteConfig{
    89  			"nuc1": {
    90  				Addr:     "https://10.0.0.1:8443",
    91  				AuthType: "certificate",
    92  				Protocol: "lxd",
    93  				Public:   false,
    94  			},
    95  		},
    96  	}, nil)
    97  
    98  	cloudDetector := deps.provider.(environs.CloudDetector)
    99  
   100  	clouds, err := cloudDetector.DetectClouds()
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	c.Assert(clouds, gc.HasLen, 2)
   103  	c.Assert(clouds, jc.DeepEquals, []cloud.Cloud{
   104  		{
   105  			Name: "localhost",
   106  			Type: "lxd",
   107  			AuthTypes: []cloud.AuthType{
   108  				cloud.CertificateAuthType,
   109  			},
   110  			Regions: []cloud.Region{{
   111  				Name: "localhost",
   112  			}},
   113  			Description: "LXD Container Hypervisor",
   114  		},
   115  		{
   116  			Name:     "nuc1",
   117  			Type:     "lxd",
   118  			Endpoint: "https://10.0.0.1:8443",
   119  			AuthTypes: []cloud.AuthType{
   120  				cloud.CertificateAuthType,
   121  			},
   122  			Regions: []cloud.Region{{
   123  				Name:     "default",
   124  				Endpoint: "https://10.0.0.1:8443",
   125  			}},
   126  			Description: "LXD Cluster",
   127  		},
   128  	})
   129  }
   130  
   131  func (s *providerSuite) TestRemoteDetectCloudsWithConfigError(c *gc.C) {
   132  	ctrl := gomock.NewController(c)
   133  	defer ctrl.Finish()
   134  
   135  	deps := s.createProvider(ctrl)
   136  	deps.configReader.EXPECT().ReadConfig(".config/lxc/config.yml").Return(lxd.LXCConfig{}, errors.New("bad"))
   137  
   138  	cloudDetector := deps.provider.(environs.CloudDetector)
   139  
   140  	clouds, err := cloudDetector.DetectClouds()
   141  	c.Assert(err, jc.ErrorIsNil)
   142  	c.Assert(clouds, gc.HasLen, 1)
   143  	s.assertLocalhostCloud(c, clouds[0])
   144  }
   145  
   146  func (s *providerSuite) TestDetectCloud(c *gc.C) {
   147  	ctrl := gomock.NewController(c)
   148  	defer ctrl.Finish()
   149  
   150  	deps := s.createProvider(ctrl)
   151  	cloudDetector := deps.provider.(environs.CloudDetector)
   152  
   153  	cloud, err := cloudDetector.DetectCloud("localhost")
   154  	c.Assert(err, jc.ErrorIsNil)
   155  	s.assertLocalhostCloud(c, cloud)
   156  	cloud, err = cloudDetector.DetectCloud("lxd")
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	s.assertLocalhostCloud(c, cloud)
   159  }
   160  
   161  func (s *providerSuite) TestRemoteDetectCloud(c *gc.C) {
   162  	ctrl := gomock.NewController(c)
   163  	defer ctrl.Finish()
   164  
   165  	deps := s.createProvider(ctrl)
   166  	cloudDetector := deps.provider.(environs.CloudDetector)
   167  
   168  	deps.configReader.EXPECT().ReadConfig(".config/lxc/config.yml").Return(lxd.LXCConfig{
   169  		DefaultRemote: "localhost",
   170  		Remotes: map[string]lxd.LXCRemoteConfig{
   171  			"nuc1": {
   172  				Addr:     "https://10.0.0.1:8443",
   173  				AuthType: "certificate",
   174  				Protocol: "lxd",
   175  				Public:   false,
   176  			},
   177  		},
   178  	}, nil)
   179  
   180  	got, err := cloudDetector.DetectCloud("nuc1")
   181  	c.Assert(err, jc.ErrorIsNil)
   182  	c.Assert(got, jc.DeepEquals, cloud.Cloud{
   183  		Name:     "nuc1",
   184  		Type:     "lxd",
   185  		Endpoint: "https://10.0.0.1:8443",
   186  		AuthTypes: []cloud.AuthType{
   187  			cloud.CertificateAuthType,
   188  		},
   189  		Regions: []cloud.Region{{
   190  			Name:     "default",
   191  			Endpoint: "https://10.0.0.1:8443",
   192  		}},
   193  		Description: "LXD Cluster",
   194  	})
   195  }
   196  
   197  func (s *providerSuite) TestRemoteDetectCloudWithConfigError(c *gc.C) {
   198  	ctrl := gomock.NewController(c)
   199  	defer ctrl.Finish()
   200  
   201  	deps := s.createProvider(ctrl)
   202  	cloudDetector := deps.provider.(environs.CloudDetector)
   203  
   204  	deps.configReader.EXPECT().ReadConfig(".config/lxc/config.yml").Return(lxd.LXCConfig{}, errors.New("bad"))
   205  
   206  	_, err := cloudDetector.DetectCloud("nuc1")
   207  	c.Assert(err, gc.ErrorMatches, `cloud nuc1 not found`)
   208  }
   209  
   210  func (s *providerSuite) TestDetectCloudError(c *gc.C) {
   211  	ctrl := gomock.NewController(c)
   212  	defer ctrl.Finish()
   213  
   214  	deps := s.createProvider(ctrl)
   215  	deps.configReader.EXPECT().ReadConfig(".config/lxc/config.yml").Return(lxd.LXCConfig{}, errors.New("bad"))
   216  
   217  	cloudDetector := deps.provider.(environs.CloudDetector)
   218  
   219  	_, err := cloudDetector.DetectCloud("foo")
   220  	c.Assert(err, gc.ErrorMatches, `cloud foo not found`)
   221  }
   222  
   223  func (s *providerSuite) assertLocalhostCloud(c *gc.C, found cloud.Cloud) {
   224  	c.Assert(found, jc.DeepEquals, cloud.Cloud{
   225  		Name: "localhost",
   226  		Type: "lxd",
   227  		AuthTypes: []cloud.AuthType{
   228  			cloud.CertificateAuthType,
   229  		},
   230  		Regions: []cloud.Region{{
   231  			Name: "localhost",
   232  		}},
   233  		Description: "LXD Container Hypervisor",
   234  	})
   235  }
   236  
   237  func (s *providerSuite) TestFinalizeCloud(c *gc.C) {
   238  	ctrl := gomock.NewController(c)
   239  	defer ctrl.Finish()
   240  
   241  	deps := s.createProvider(ctrl)
   242  	server := lxd.NewMockServer(ctrl)
   243  	finalizer := deps.provider.(environs.CloudFinalizer)
   244  
   245  	deps.factory.EXPECT().LocalServer().Return(server, nil)
   246  	server.EXPECT().LocalBridgeName().Return("lxdbr0")
   247  	deps.factory.EXPECT().LocalServerAddress().Return("1.2.3.4:1234", nil)
   248  
   249  	var ctx mockContext
   250  	out, err := finalizer.FinalizeCloud(&ctx, cloud.Cloud{
   251  		Name:      "localhost",
   252  		Type:      "lxd",
   253  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   254  		Regions: []cloud.Region{{
   255  			Name: "localhost",
   256  		}},
   257  	})
   258  	c.Assert(err, jc.ErrorIsNil)
   259  	c.Assert(out, jc.DeepEquals, cloud.Cloud{
   260  		Name:      "localhost",
   261  		Type:      "lxd",
   262  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   263  		Endpoint:  "1.2.3.4:1234",
   264  		Regions: []cloud.Region{{
   265  			Name:     "localhost",
   266  			Endpoint: "1.2.3.4:1234",
   267  		}},
   268  	})
   269  	ctx.CheckCallNames(c, "Verbosef")
   270  	ctx.CheckCall(
   271  		c, 0, "Verbosef", "Resolved LXD host address on bridge %s: %s",
   272  		[]interface{}{"lxdbr0", "1.2.3.4:1234"},
   273  	)
   274  }
   275  
   276  func (s *providerSuite) TestFinalizeCloudWithRemoteProvider(c *gc.C) {
   277  	ctrl := gomock.NewController(c)
   278  	defer ctrl.Finish()
   279  
   280  	deps := s.createProvider(ctrl)
   281  	finalizer := deps.provider.(environs.CloudFinalizer)
   282  
   283  	var ctx mockContext
   284  	out, err := finalizer.FinalizeCloud(&ctx, cloud.Cloud{
   285  		Name:      "nuc8",
   286  		Type:      "lxd",
   287  		Endpoint:  "http://10.0.0.1:8443",
   288  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   289  		Regions:   []cloud.Region{},
   290  	})
   291  	c.Assert(err, jc.ErrorIsNil)
   292  	c.Assert(out, jc.DeepEquals, cloud.Cloud{
   293  		Name:      "nuc8",
   294  		Type:      "lxd",
   295  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   296  		Endpoint:  "http://10.0.0.1:8443",
   297  		Regions: []cloud.Region{{
   298  			Name:     "default",
   299  			Endpoint: "http://10.0.0.1:8443",
   300  		}},
   301  	})
   302  }
   303  
   304  func (s *providerSuite) TestFinalizeCloudWithRemoteProviderWithOnlyRegionEndpoint(c *gc.C) {
   305  	ctrl := gomock.NewController(c)
   306  	defer ctrl.Finish()
   307  
   308  	deps := s.createProvider(ctrl)
   309  	cloudFinalizer := deps.provider.(environs.CloudFinalizer)
   310  
   311  	cloudSpec := cloud.Cloud{
   312  		Name:      "foo",
   313  		Type:      "lxd",
   314  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   315  		Regions: []cloud.Region{{
   316  			Name:     "bar",
   317  			Endpoint: "https://321.321.12.12",
   318  		}},
   319  	}
   320  
   321  	ctx := testing.NewMockFinalizeCloudContext(ctrl)
   322  	got, err := cloudFinalizer.FinalizeCloud(ctx, cloudSpec)
   323  	c.Assert(err, jc.ErrorIsNil)
   324  	c.Assert(got, gc.DeepEquals, cloudSpec)
   325  }
   326  
   327  func (s *providerSuite) TestFinalizeCloudWithRemoteProviderWithMixedRegions(c *gc.C) {
   328  	ctrl := gomock.NewController(c)
   329  	defer ctrl.Finish()
   330  
   331  	deps := s.createProvider(ctrl)
   332  	cloudFinalizer := deps.provider.(environs.CloudFinalizer)
   333  
   334  	server := lxd.NewMockServer(ctrl)
   335  
   336  	deps.factory.EXPECT().LocalServer().Return(server, nil)
   337  	server.EXPECT().LocalBridgeName().Return("lxdbr0")
   338  	deps.factory.EXPECT().LocalServerAddress().Return("https://192.0.0.1:8443", nil)
   339  
   340  	cloudSpec := cloud.Cloud{
   341  		Name:      "localhost",
   342  		Type:      "lxd",
   343  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   344  		Regions: []cloud.Region{{
   345  			Name:     "bar",
   346  			Endpoint: "https://321.321.12.12",
   347  		}},
   348  	}
   349  
   350  	ctx := testing.NewMockFinalizeCloudContext(ctrl)
   351  	ctx.EXPECT().Verbosef("Resolved LXD host address on bridge %s: %s", "lxdbr0", "https://192.0.0.1:8443")
   352  
   353  	got, err := cloudFinalizer.FinalizeCloud(ctx, cloudSpec)
   354  	c.Assert(err, jc.ErrorIsNil)
   355  	c.Assert(got, gc.DeepEquals, cloud.Cloud{
   356  		Name:      "localhost",
   357  		Type:      "lxd",
   358  		Endpoint:  "https://192.0.0.1:8443",
   359  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   360  		Regions: []cloud.Region{{
   361  			Name:     "bar",
   362  			Endpoint: "https://321.321.12.12",
   363  		}},
   364  	})
   365  }
   366  
   367  func (s *providerSuite) TestFinalizeCloudWithRemoteProviderWithNoRegion(c *gc.C) {
   368  	ctrl := gomock.NewController(c)
   369  	defer ctrl.Finish()
   370  
   371  	deps := s.createProvider(ctrl)
   372  	cloudFinalizer := deps.provider.(environs.CloudFinalizer)
   373  
   374  	cloudSpec := cloud.Cloud{
   375  		Name:      "test",
   376  		Type:      "lxd",
   377  		Endpoint:  "https://192.0.0.1:8443",
   378  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   379  		Regions:   []cloud.Region{},
   380  	}
   381  
   382  	ctx := testing.NewMockFinalizeCloudContext(ctrl)
   383  
   384  	got, err := cloudFinalizer.FinalizeCloud(ctx, cloudSpec)
   385  	c.Assert(err, jc.ErrorIsNil)
   386  	c.Assert(got, gc.DeepEquals, cloud.Cloud{
   387  		Name:      "test",
   388  		Type:      "lxd",
   389  		Endpoint:  "https://192.0.0.1:8443",
   390  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   391  		Regions: []cloud.Region{{
   392  			Name:     "default",
   393  			Endpoint: "https://192.0.0.1:8443",
   394  		}},
   395  	})
   396  }
   397  
   398  func (s *providerSuite) TestFinalizeCloudNotListening(c *gc.C) {
   399  	ctrl := gomock.NewController(c)
   400  	defer ctrl.Finish()
   401  
   402  	deps := s.createProvider(ctrl)
   403  	cloudFinalizer := deps.provider.(environs.CloudFinalizer)
   404  
   405  	deps.factory.EXPECT().LocalServer().Return(nil, errors.New("bad"))
   406  
   407  	ctx := testing.NewMockFinalizeCloudContext(ctrl)
   408  	_, err := cloudFinalizer.FinalizeCloud(ctx, cloud.Cloud{
   409  		Name:      "localhost",
   410  		Type:      "lxd",
   411  		AuthTypes: []cloud.AuthType{cloud.CertificateAuthType},
   412  		Regions: []cloud.Region{{
   413  			Name: "bar",
   414  		}},
   415  	})
   416  	c.Assert(err, gc.NotNil)
   417  	c.Assert(err, gc.ErrorMatches, "bad")
   418  }
   419  
   420  func (s *providerSuite) TestDetectRegions(c *gc.C) {
   421  	ctrl := gomock.NewController(c)
   422  	defer ctrl.Finish()
   423  
   424  	deps := s.createProvider(ctrl)
   425  	cloudDetector := deps.provider.(environs.CloudRegionDetector)
   426  
   427  	regions, err := cloudDetector.DetectRegions()
   428  	c.Assert(err, jc.ErrorIsNil)
   429  	c.Assert(regions, jc.DeepEquals, []cloud.Region{{Name: lxdnames.DefaultLocalRegion}})
   430  }
   431  
   432  func (s *providerSuite) TestValidate(c *gc.C) {
   433  	ctrl := gomock.NewController(c)
   434  	defer ctrl.Finish()
   435  
   436  	deps := s.createProvider(ctrl)
   437  
   438  	validCfg, err := deps.provider.Validate(s.Config, nil)
   439  	c.Assert(err, jc.ErrorIsNil)
   440  	validAttrs := validCfg.AllAttrs()
   441  
   442  	c.Check(s.Config.AllAttrs(), gc.DeepEquals, validAttrs)
   443  }
   444  
   445  func (s *providerSuite) TestValidateWithInvalidConfig(c *gc.C) {
   446  	ctrl := gomock.NewController(c)
   447  	defer ctrl.Finish()
   448  
   449  	deps := s.createProvider(ctrl)
   450  
   451  	config, err := jujutesting.ModelConfig(c).Apply(map[string]interface{}{
   452  		"value": int64(1),
   453  	})
   454  	c.Assert(err, gc.IsNil)
   455  
   456  	_, err = deps.provider.Validate(config, nil)
   457  	c.Assert(err, gc.NotNil)
   458  }
   459  
   460  func (s *providerSuite) TestCloudSchema(c *gc.C) {
   461  	ctrl := gomock.NewController(c)
   462  	defer ctrl.Finish()
   463  
   464  	deps := s.createProvider(ctrl)
   465  
   466  	config := `
   467  auth-types: [certificate]
   468  endpoint: http://foo.com/lxd
   469  `[1:]
   470  	var v interface{}
   471  	err := yaml.Unmarshal([]byte(config), &v)
   472  	c.Assert(err, jc.ErrorIsNil)
   473  	v, err = utils.ConformYAML(v)
   474  	c.Assert(err, jc.ErrorIsNil)
   475  
   476  	err = deps.provider.CloudSchema().Validate(v)
   477  	c.Assert(err, jc.ErrorIsNil)
   478  }
   479  
   480  func (s *providerSuite) TestPingFailWithNoEndpoint(c *gc.C) {
   481  	server := httptest.NewTLSServer(http.HandlerFunc(http.NotFound))
   482  	defer server.Close()
   483  
   484  	p, err := environs.Provider("lxd")
   485  	c.Assert(err, jc.ErrorIsNil)
   486  	err = p.Ping(context.NewCloudCallContext(), server.URL)
   487  	c.Assert(err, gc.ErrorMatches, "no lxd server running at "+server.URL)
   488  }
   489  
   490  func (s *providerSuite) TestPingFailWithHTTP(c *gc.C) {
   491  	server := httptest.NewServer(http.HandlerFunc(http.NotFound))
   492  	defer server.Close()
   493  
   494  	p, err := environs.Provider("lxd")
   495  	c.Assert(err, jc.ErrorIsNil)
   496  	err = p.Ping(context.NewCloudCallContext(), server.URL)
   497  	c.Assert(err, gc.ErrorMatches, "invalid URL \""+server.URL+"\": only HTTPS is supported")
   498  }
   499  
   500  type ProviderFunctionalSuite struct {
   501  	lxd.BaseSuite
   502  
   503  	provider environs.EnvironProvider
   504  }
   505  
   506  func (s *ProviderFunctionalSuite) SetUpTest(c *gc.C) {
   507  	if !s.IsRunningLocally(c) {
   508  		c.Skip("LXD not running locally")
   509  	}
   510  
   511  	s.BaseSuite.SetUpTest(c)
   512  
   513  	provider, err := environs.Provider("lxd")
   514  	c.Assert(err, jc.ErrorIsNil)
   515  
   516  	s.provider = provider
   517  }
   518  
   519  func (s *ProviderFunctionalSuite) TestOpen(c *gc.C) {
   520  	env, err := environs.Open(s.provider, environs.OpenParams{
   521  		Cloud:  lxdCloudSpec(),
   522  		Config: s.Config,
   523  	})
   524  	c.Assert(err, jc.ErrorIsNil)
   525  	envConfig := env.Config()
   526  
   527  	c.Check(envConfig.Name(), gc.Equals, "testmodel")
   528  }
   529  
   530  func (s *ProviderFunctionalSuite) TestPrepareConfig(c *gc.C) {
   531  	cfg, err := s.provider.PrepareConfig(environs.PrepareConfigParams{
   532  		Cloud:  lxdCloudSpec(),
   533  		Config: s.Config,
   534  	})
   535  	c.Assert(err, jc.ErrorIsNil)
   536  	c.Check(cfg, gc.NotNil)
   537  }
   538  
   539  func (s *ProviderFunctionalSuite) TestPrepareConfigUnsupportedEndpointScheme(c *gc.C) {
   540  	cloudSpec := lxdCloudSpec()
   541  	cloudSpec.Endpoint = "unix://foo"
   542  	_, err := s.provider.PrepareConfig(environs.PrepareConfigParams{
   543  		Cloud:  cloudSpec,
   544  		Config: s.Config,
   545  	})
   546  	c.Assert(err, gc.ErrorMatches, `validating cloud spec: invalid URL "unix://foo": only HTTPS is supported`)
   547  }
   548  
   549  func (s *ProviderFunctionalSuite) TestPrepareConfigUnsupportedAuthType(c *gc.C) {
   550  	cred := cloud.NewCredential("foo", nil)
   551  	_, err := s.provider.PrepareConfig(environs.PrepareConfigParams{
   552  		Cloud: environs.CloudSpec{
   553  			Type:       "lxd",
   554  			Name:       "remotehost",
   555  			Credential: &cred,
   556  		},
   557  	})
   558  	c.Assert(err, gc.ErrorMatches, `validating cloud spec: "foo" auth-type not supported`)
   559  }
   560  
   561  func (s *ProviderFunctionalSuite) TestPrepareConfigInvalidCertificateAttrs(c *gc.C) {
   562  	cred := cloud.NewCredential(cloud.CertificateAuthType, map[string]string{})
   563  	_, err := s.provider.PrepareConfig(environs.PrepareConfigParams{
   564  		Cloud: environs.CloudSpec{
   565  			Type:       "lxd",
   566  			Name:       "remotehost",
   567  			Credential: &cred,
   568  		},
   569  	})
   570  	c.Assert(err, gc.ErrorMatches, `validating cloud spec: certificate credentials not valid`)
   571  }
   572  
   573  func (s *ProviderFunctionalSuite) TestPrepareConfigEmptyAuthNonLocal(c *gc.C) {
   574  	cred := cloud.NewEmptyCredential()
   575  	_, err := s.provider.PrepareConfig(environs.PrepareConfigParams{
   576  		Cloud: environs.CloudSpec{
   577  			Type:       "lxd",
   578  			Name:       "remotehost",
   579  			Endpoint:   "8.8.8.8",
   580  			Credential: &cred,
   581  		},
   582  	})
   583  	c.Assert(err, gc.ErrorMatches, `validating cloud spec: "empty" auth-type not supported`)
   584  }
   585  
   586  type mockContext struct {
   587  	gitjujutesting.Stub
   588  }
   589  
   590  func (c *mockContext) Verbosef(f string, args ...interface{}) {
   591  	c.MethodCall(c, "Verbosef", f, args)
   592  }