github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/cmd/juju/cloud/updateclouds_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package cloud_test
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"net/http"
    10  	"net/http/httptest"
    11  	"strings"
    12  
    13  	jc "github.com/juju/testing/checkers"
    14  	"golang.org/x/crypto/openpgp"
    15  	"golang.org/x/crypto/openpgp/clearsign"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	jujucloud "github.com/juju/juju/cloud"
    19  	"github.com/juju/juju/cmd/juju/cloud"
    20  	sstesting "github.com/juju/juju/environs/simplestreams/testing"
    21  	"github.com/juju/juju/juju/osenv"
    22  	"github.com/juju/juju/testing"
    23  )
    24  
    25  type updateCloudsSuite struct {
    26  	testing.BaseSuite
    27  }
    28  
    29  var _ = gc.Suite(&updateCloudsSuite{})
    30  
    31  func (s *updateCloudsSuite) SetUpTest(c *gc.C) {
    32  	origHome := osenv.SetJujuXDGDataHome(c.MkDir())
    33  	s.AddCleanup(func(*gc.C) { osenv.SetJujuXDGDataHome(origHome) })
    34  }
    35  
    36  func encodeCloudYAML(c *gc.C, yaml string) string {
    37  	// TODO(wallyworld) - move test signing key elsewhere
    38  	keyring, err := openpgp.ReadArmoredKeyRing(bytes.NewBufferString(sstesting.SignedMetadataPrivateKey))
    39  	c.Assert(err, jc.ErrorIsNil)
    40  	privateKey := keyring[0].PrivateKey
    41  	err = privateKey.Decrypt([]byte(sstesting.PrivateKeyPassphrase))
    42  	c.Assert(err, jc.ErrorIsNil)
    43  
    44  	var buf bytes.Buffer
    45  	plaintext, err := clearsign.Encode(&buf, privateKey, nil)
    46  	c.Assert(err, jc.ErrorIsNil)
    47  
    48  	_, err = plaintext.Write([]byte(yaml))
    49  	c.Assert(err, jc.ErrorIsNil)
    50  	err = plaintext.Close()
    51  	c.Assert(err, jc.ErrorIsNil)
    52  	return string(buf.Bytes())
    53  }
    54  
    55  func (s *updateCloudsSuite) setupTestServer(c *gc.C, serverContent string) *httptest.Server {
    56  	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    57  		switch serverContent {
    58  		case "404":
    59  			w.WriteHeader(http.StatusNotFound)
    60  		case "401":
    61  			w.WriteHeader(http.StatusUnauthorized)
    62  		case "unsigned":
    63  			fmt.Fprintln(w, serverContent)
    64  			return
    65  		}
    66  		signedContent := encodeCloudYAML(c, serverContent)
    67  		fmt.Fprintln(w, signedContent)
    68  	}))
    69  }
    70  
    71  func (s *updateCloudsSuite) TestBadArgs(c *gc.C) {
    72  	updateCmd := cloud.NewUpdateCloudsCommandForTest("")
    73  	_, err := testing.RunCommand(c, updateCmd, "extra")
    74  	c.Assert(err, gc.ErrorMatches, `unrecognized args: \["extra"\]`)
    75  }
    76  
    77  func (s *updateCloudsSuite) run(c *gc.C, url, errMsg string) string {
    78  	updateCmd := cloud.NewUpdateCloudsCommandForTest(url)
    79  	out, err := testing.RunCommand(c, updateCmd)
    80  	if errMsg == "" {
    81  		c.Assert(err, jc.ErrorIsNil)
    82  	} else {
    83  		errString := strings.Replace(err.Error(), "\n", "", -1)
    84  		c.Assert(errString, gc.Matches, errMsg)
    85  	}
    86  	return testing.Stdout(out)
    87  }
    88  
    89  func (s *updateCloudsSuite) Test404(c *gc.C) {
    90  	ts := s.setupTestServer(c, "404")
    91  	defer ts.Close()
    92  
    93  	msg := s.run(c, ts.URL, "")
    94  	c.Assert(strings.Replace(msg, "\n", "", -1), gc.Matches, "Fetching latest public cloud list...Public cloud list is unavailable right now.")
    95  }
    96  
    97  func (s *updateCloudsSuite) Test401(c *gc.C) {
    98  	ts := s.setupTestServer(c, "401")
    99  	defer ts.Close()
   100  
   101  	s.run(c, ts.URL, "unauthorised access to URL .*")
   102  }
   103  
   104  func (s *updateCloudsSuite) TestUnsignedData(c *gc.C) {
   105  	ts := s.setupTestServer(c, "unsigned")
   106  	defer ts.Close()
   107  
   108  	s.run(c, ts.URL, "error receiving updated cloud data: no PGP signature embedded in plain text data")
   109  }
   110  
   111  func (s *updateCloudsSuite) TestBadDataOnServer(c *gc.C) {
   112  	ts := s.setupTestServer(c, "bad data")
   113  	defer ts.Close()
   114  
   115  	s.run(c, ts.URL, ".*invalid cloud data received when updating clouds.*")
   116  }
   117  
   118  var sampleUpdateCloudData = `
   119  clouds:
   120    aws:
   121      type: ec2
   122      auth-types: [access-key]
   123      endpoint: http://region
   124      regions:
   125        region:
   126          endpoint: http://region/1.0
   127  `[1:]
   128  
   129  func (s *updateCloudsSuite) TestNoNewData(c *gc.C) {
   130  	clouds, err := jujucloud.ParseCloudMetadata([]byte(sampleUpdateCloudData))
   131  	c.Assert(err, jc.ErrorIsNil)
   132  	err = jujucloud.WritePublicCloudMetadata(clouds)
   133  	c.Assert(err, jc.ErrorIsNil)
   134  
   135  	ts := s.setupTestServer(c, sampleUpdateCloudData)
   136  	defer ts.Close()
   137  
   138  	msg := s.run(c, ts.URL, "")
   139  	c.Assert(strings.Replace(msg, "\n", "", -1), gc.Matches, "Fetching latest public cloud list...Your list of public clouds is up to date, see juju list-clouds.")
   140  }
   141  
   142  func (s *updateCloudsSuite) TestFirstRun(c *gc.C) {
   143  	// make sure there is nothing
   144  	err := jujucloud.WritePublicCloudMetadata(nil)
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	ts := s.setupTestServer(c, sampleUpdateCloudData)
   148  	defer ts.Close()
   149  
   150  	msg := s.run(c, ts.URL, "")
   151  	publicClouds, fallbackUsed, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath())
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	c.Assert(fallbackUsed, jc.IsFalse)
   154  	clouds, err := jujucloud.ParseCloudMetadata([]byte(sampleUpdateCloudData))
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	c.Assert(publicClouds, jc.DeepEquals, clouds)
   157  	c.Assert(msg, gc.Matches, `
   158  Fetching latest public cloud list...
   159  Updated your list of public clouds with 1 cloud added:
   160  
   161      added cloud:
   162          - aws
   163  `[1:])
   164  }
   165  
   166  func (s *updateCloudsSuite) TestNewData(c *gc.C) {
   167  	clouds, err := jujucloud.ParseCloudMetadata([]byte(sampleUpdateCloudData))
   168  	c.Assert(err, jc.ErrorIsNil)
   169  	err = jujucloud.WritePublicCloudMetadata(clouds)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  
   172  	newUpdateCloudData := sampleUpdateCloudData + `
   173        anotherregion:
   174          endpoint: http://anotherregion/1.0
   175  `[1:]
   176  	ts := s.setupTestServer(c, newUpdateCloudData)
   177  	defer ts.Close()
   178  
   179  	msg := s.run(c, ts.URL, "")
   180  	publicClouds, fallbackUsed, err := jujucloud.PublicCloudMetadata(jujucloud.JujuPublicCloudsPath())
   181  	c.Assert(err, jc.ErrorIsNil)
   182  	c.Assert(fallbackUsed, jc.IsFalse)
   183  	clouds, err = jujucloud.ParseCloudMetadata([]byte(newUpdateCloudData))
   184  	c.Assert(err, jc.ErrorIsNil)
   185  	c.Assert(publicClouds, jc.DeepEquals, clouds)
   186  	c.Assert(msg, gc.Matches, `
   187  Fetching latest public cloud list...
   188  Updated your list of public clouds with 1 cloud region added:
   189  
   190      added cloud region:
   191          - aws/anotherregion
   192  `[1:])
   193  }