github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/tools/lxdclient/remote_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build go1.3
     5  
     6  package lxdclient_test
     7  
     8  import (
     9  	"net"
    10  
    11  	"github.com/juju/errors"
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	"github.com/juju/juju/tools/lxdclient"
    16  )
    17  
    18  var (
    19  	_ = gc.Suite(&remoteSuite{})
    20  )
    21  
    22  type remoteSuite struct {
    23  	lxdclient.BaseSuite
    24  }
    25  
    26  const (
    27  	testingCert = `
    28  -----BEGIN CERTIFICATE-----
    29  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
    60  EiFwoj8EbmwqzbNpOTNAOdo=
    61  -----END CERTIFICATE-----
    62  `
    63  
    64  	testingKey = `
    65  -----BEGIN RSA PRIVATE KEY-----
    66  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
   115  -----END RSA PRIVATE KEY-----
   116  `
   117  )
   118  
   119  func (s *remoteSuite) TestWithDefaultsNoop(c *gc.C) {
   120  	remote := lxdclient.Remote{
   121  		Name:     "my-remote",
   122  		Host:     "some-host",
   123  		Protocol: lxdclient.LXDProtocol,
   124  		Cert:     s.Cert,
   125  	}
   126  	updated, err := remote.WithDefaults()
   127  	c.Assert(err, jc.ErrorIsNil)
   128  	err = updated.Validate()
   129  
   130  	c.Check(err, jc.ErrorIsNil)
   131  	c.Check(updated, jc.DeepEquals, remote)
   132  }
   133  
   134  func (s *remoteSuite) TestWithDefaultsMissingName(c *gc.C) {
   135  	remote := lxdclient.Remote{
   136  		Name:     "",
   137  		Host:     "some-host",
   138  		Protocol: lxdclient.LXDProtocol,
   139  		Cert:     s.Cert,
   140  	}
   141  	updated, err := remote.WithDefaults()
   142  	c.Assert(err, jc.ErrorIsNil)
   143  
   144  	c.Check(updated, jc.DeepEquals, remote) // Name is not updated.
   145  }
   146  
   147  // TODO(ericsnow) Move this test to a functional suite.
   148  func (s *remoteSuite) TestWithDefaultsMissingCert(c *gc.C) {
   149  	lxdclient.PatchGenerateCertificate(&s.CleanupSuite, testingCert, testingKey)
   150  	remote := lxdclient.Remote{
   151  		Name:     "my-remote",
   152  		Host:     "some-host",
   153  		Protocol: lxdclient.LXDProtocol,
   154  		Cert:     nil,
   155  	}
   156  	updated, err := remote.WithDefaults()
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	err = updated.Validate()
   159  
   160  	c.Check(err, jc.ErrorIsNil)
   161  	c.Assert(updated.Cert, gc.NotNil)
   162  	c.Check(updated.Cert.Validate(), jc.ErrorIsNil)
   163  	updated.Cert = nil // Validate ensured that the cert was okay.
   164  	c.Check(updated, jc.DeepEquals, lxdclient.Remote{
   165  		Name:     "my-remote",
   166  		Host:     "some-host",
   167  		Protocol: lxdclient.LXDProtocol,
   168  		Cert:     nil,
   169  	})
   170  }
   171  
   172  func (s *remoteSuite) TestWithDefaultsMissingProtocol(c *gc.C) {
   173  	remote := lxdclient.Remote{
   174  		Name: "my-remote",
   175  		Host: "some-host",
   176  		Cert: s.Cert,
   177  	}
   178  	updated, err := remote.WithDefaults()
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	err = updated.Validate()
   181  
   182  	c.Check(err, jc.ErrorIsNil)
   183  	c.Assert(updated.Cert, gc.NotNil)
   184  	c.Check(updated.Cert.Validate(), jc.ErrorIsNil)
   185  	updated.Cert = nil // Validate ensured that the cert was okay.
   186  	c.Check(updated, jc.DeepEquals, lxdclient.Remote{
   187  		Name:     "my-remote",
   188  		Host:     "some-host",
   189  		Protocol: lxdclient.LXDProtocol,
   190  		Cert:     nil,
   191  	})
   192  }
   193  
   194  func (s *remoteSuite) TestWithDefaultsZeroValue(c *gc.C) {
   195  	var remote lxdclient.Remote
   196  	updated, err := remote.WithDefaults()
   197  	c.Assert(err, jc.ErrorIsNil)
   198  	err = updated.Validate()
   199  
   200  	c.Check(err, jc.ErrorIsNil)
   201  	c.Check(updated, jc.DeepEquals, lxdclient.Remote{
   202  		Name:     "local",
   203  		Host:     "",
   204  		Protocol: lxdclient.LXDProtocol,
   205  		Cert:     nil,
   206  	})
   207  }
   208  
   209  func (s *remoteSuite) TestWithDefaultsLocalNoop(c *gc.C) {
   210  	remote := lxdclient.Remote{
   211  		Name: "my-local",
   212  		Host: "",
   213  		Cert: nil,
   214  	}
   215  	updated, err := remote.WithDefaults()
   216  	c.Assert(err, jc.ErrorIsNil)
   217  	err = updated.Validate()
   218  
   219  	c.Check(err, jc.ErrorIsNil)
   220  	c.Check(updated, jc.DeepEquals, lxdclient.Remote{
   221  		Name:     "my-local",
   222  		Host:     "",
   223  		Protocol: lxdclient.LXDProtocol,
   224  		Cert:     nil,
   225  	})
   226  }
   227  
   228  func (s *remoteSuite) TestWithDefaultsLocalMissingName(c *gc.C) {
   229  	remote := lxdclient.Remote{
   230  		Name: "",
   231  		Host: "",
   232  		Cert: nil,
   233  	}
   234  	updated, err := remote.WithDefaults()
   235  	c.Assert(err, jc.ErrorIsNil)
   236  	err = updated.Validate()
   237  
   238  	c.Check(err, jc.ErrorIsNil)
   239  	c.Check(updated, jc.DeepEquals, lxdclient.Remote{
   240  		Name:     "local",
   241  		Host:     "",
   242  		Cert:     nil,
   243  		Protocol: lxdclient.LXDProtocol,
   244  	})
   245  }
   246  
   247  func (s *remoteSuite) TestValidateOkay(c *gc.C) {
   248  	remote := lxdclient.Remote{
   249  		Name:     "my-remote",
   250  		Host:     "some-host",
   251  		Protocol: lxdclient.LXDProtocol,
   252  		Cert:     s.Cert,
   253  	}
   254  	err := remote.Validate()
   255  
   256  	c.Check(err, jc.ErrorIsNil)
   257  }
   258  
   259  func (s *remoteSuite) TestValidateZeroValue(c *gc.C) {
   260  	var remote lxdclient.Remote
   261  	err := remote.Validate()
   262  
   263  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   264  }
   265  
   266  func (s *remoteSuite) TestValidateMissingName(c *gc.C) {
   267  	remote := lxdclient.Remote{
   268  		Name:     "",
   269  		Host:     "some-host",
   270  		Protocol: lxdclient.LXDProtocol,
   271  		Cert:     s.Cert,
   272  	}
   273  	err := remote.Validate()
   274  
   275  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   276  }
   277  
   278  func (s *remoteSuite) TestValidateMissingCert(c *gc.C) {
   279  	// We can have "public" remotes that don't require a client certificate
   280  	// to connect to and get images from.
   281  	remote := lxdclient.Remote{
   282  		Name:     "my-remote",
   283  		Host:     "some-host",
   284  		Protocol: lxdclient.LXDProtocol,
   285  		Cert:     nil,
   286  	}
   287  	err := remote.Validate()
   288  
   289  	c.Check(err, jc.ErrorIsNil)
   290  }
   291  
   292  func (s *remoteSuite) TestValidateBadCert(c *gc.C) {
   293  	remote := lxdclient.Remote{
   294  		Name:     "my-remote",
   295  		Host:     "some-host",
   296  		Protocol: lxdclient.LXDProtocol,
   297  		Cert:     &lxdclient.Cert{},
   298  	}
   299  	err := remote.Validate()
   300  
   301  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   302  }
   303  
   304  func (s *remoteSuite) TestValidateLocalOkay(c *gc.C) {
   305  	remote := lxdclient.Remote{
   306  		Name:     "my-local",
   307  		Host:     "",
   308  		Protocol: lxdclient.LXDProtocol,
   309  		Cert:     nil,
   310  	}
   311  	err := remote.Validate()
   312  
   313  	c.Check(err, jc.ErrorIsNil)
   314  }
   315  
   316  func (s *remoteSuite) TestValidateLocalMissingName(c *gc.C) {
   317  	remote := lxdclient.Remote{
   318  		Name:     "",
   319  		Host:     "",
   320  		Protocol: lxdclient.LXDProtocol,
   321  		Cert:     nil,
   322  	}
   323  	err := remote.Validate()
   324  
   325  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   326  }
   327  
   328  func (s *remoteSuite) TestValidateLocalSimplestreamsInvalid(c *gc.C) {
   329  	remote := lxdclient.Remote{
   330  		Name:     "",
   331  		Host:     "",
   332  		Protocol: lxdclient.SimplestreamsProtocol,
   333  		Cert:     nil,
   334  	}
   335  	err := remote.Validate()
   336  
   337  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   338  }
   339  
   340  func (s *remoteSuite) TestValidateLocalWithCert(c *gc.C) {
   341  	remote := lxdclient.Remote{
   342  		Name:     "my-local",
   343  		Host:     "",
   344  		Protocol: lxdclient.LXDProtocol,
   345  		Cert:     &lxdclient.Cert{},
   346  	}
   347  	err := remote.Validate()
   348  
   349  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   350  }
   351  
   352  func (s *remoteSuite) TestValidateSimplestreamsOkay(c *gc.C) {
   353  	remote := lxdclient.Remote{
   354  		Name:     "remote",
   355  		Host:     "http://somewhere/else",
   356  		Protocol: lxdclient.SimplestreamsProtocol,
   357  		Cert:     nil,
   358  	}
   359  	err := remote.Validate()
   360  
   361  	c.Check(err, jc.ErrorIsNil)
   362  }
   363  
   364  func (s *remoteSuite) TestValidateUnknownProtocol(c *gc.C) {
   365  	remote := lxdclient.Remote{
   366  		Name:     "remote",
   367  		Host:     "http://somewhere/else",
   368  		Protocol: "bogus-protocol",
   369  		Cert:     nil,
   370  	}
   371  	err := remote.Validate()
   372  
   373  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   374  }
   375  
   376  func (s *remoteSuite) TestLocal(c *gc.C) {
   377  	expected := lxdclient.Remote{
   378  		Name:     "local",
   379  		Host:     "",
   380  		Protocol: lxdclient.LXDProtocol,
   381  		Cert:     nil,
   382  	}
   383  	c.Check(lxdclient.Local, jc.DeepEquals, expected)
   384  }
   385  
   386  func (s *remoteSuite) TestIDOkay(c *gc.C) {
   387  	remote := lxdclient.Remote{
   388  		Name: "my-remote",
   389  		Host: "some-host",
   390  		Cert: s.Cert,
   391  	}
   392  	id := remote.ID()
   393  
   394  	c.Check(id, gc.Equals, "my-remote")
   395  }
   396  
   397  func (s *remoteSuite) TestIDLocal(c *gc.C) {
   398  	remote := lxdclient.Remote{
   399  		Name: "my-remote",
   400  		Host: "",
   401  		Cert: s.Cert,
   402  	}
   403  	id := remote.ID()
   404  
   405  	c.Check(id, gc.Equals, "local")
   406  }
   407  
   408  func isValidAddr(value interface{}) bool {
   409  	addr, ok := value.(string)
   410  	if !ok {
   411  		return false
   412  	}
   413  	return net.ParseIP(addr) != nil
   414  }