github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/worker/uniter/charm/bundles_test.go (about)

     1  // Copyright 2012-2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package charm_test
     5  
     6  import (
     7  	"crypto/sha256"
     8  	"encoding/hex"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"net/url"
    12  	"os"
    13  	"path/filepath"
    14  	"regexp"
    15  	"time"
    16  
    17  	gitjujutesting "github.com/juju/testing"
    18  	jc "github.com/juju/testing/checkers"
    19  	"github.com/juju/utils"
    20  	gc "gopkg.in/check.v1"
    21  	corecharm "gopkg.in/juju/charm.v6-unstable"
    22  
    23  	"github.com/juju/juju/api"
    24  	"github.com/juju/juju/api/uniter"
    25  	"github.com/juju/juju/juju/testing"
    26  	"github.com/juju/juju/state"
    27  	"github.com/juju/juju/testcharms"
    28  	coretesting "github.com/juju/juju/testing"
    29  	"github.com/juju/juju/worker/uniter/charm"
    30  )
    31  
    32  type BundlesDirSuite struct {
    33  	gitjujutesting.HTTPSuite
    34  	testing.JujuConnSuite
    35  
    36  	st     api.Connection
    37  	uniter *uniter.State
    38  }
    39  
    40  var _ = gc.Suite(&BundlesDirSuite{})
    41  
    42  func (s *BundlesDirSuite) SetUpSuite(c *gc.C) {
    43  	s.HTTPSuite.SetUpSuite(c)
    44  	s.JujuConnSuite.SetUpSuite(c)
    45  }
    46  
    47  func (s *BundlesDirSuite) TearDownSuite(c *gc.C) {
    48  	s.JujuConnSuite.TearDownSuite(c)
    49  	s.HTTPSuite.TearDownSuite(c)
    50  }
    51  
    52  func (s *BundlesDirSuite) SetUpTest(c *gc.C) {
    53  	s.HTTPSuite.SetUpTest(c)
    54  	s.JujuConnSuite.SetUpTest(c)
    55  
    56  	// Add a charm, service and unit to login to the API with.
    57  	charm := s.AddTestingCharm(c, "wordpress")
    58  	service := s.AddTestingService(c, "wordpress", charm)
    59  	unit, err := service.AddUnit()
    60  	c.Assert(err, jc.ErrorIsNil)
    61  	password, err := utils.RandomPassword()
    62  	c.Assert(err, jc.ErrorIsNil)
    63  	err = unit.SetPassword(password)
    64  	c.Assert(err, jc.ErrorIsNil)
    65  
    66  	s.st = s.OpenAPIAs(c, unit.Tag(), password)
    67  	c.Assert(s.st, gc.NotNil)
    68  	s.uniter, err = s.st.Uniter()
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	c.Assert(s.uniter, gc.NotNil)
    71  }
    72  
    73  func (s *BundlesDirSuite) TearDownTest(c *gc.C) {
    74  	err := s.st.Close()
    75  	c.Assert(err, jc.ErrorIsNil)
    76  	s.JujuConnSuite.TearDownTest(c)
    77  	s.HTTPSuite.TearDownTest(c)
    78  }
    79  
    80  func (s *BundlesDirSuite) AddCharm(c *gc.C) (charm.BundleInfo, *state.Charm, []byte) {
    81  	curl := corecharm.MustParseURL("cs:quantal/dummy-1")
    82  	storagePath := "dummy-1"
    83  	bunpath := testcharms.Repo.CharmArchivePath(c.MkDir(), "dummy")
    84  	bun, err := corecharm.ReadCharmArchive(bunpath)
    85  	c.Assert(err, jc.ErrorIsNil)
    86  	bundata, hash := readHash(c, bunpath)
    87  	info := state.CharmInfo{
    88  		Charm:       bun,
    89  		ID:          curl,
    90  		StoragePath: storagePath,
    91  		SHA256:      hash,
    92  	}
    93  	sch, err := s.State.AddCharm(info)
    94  	c.Assert(err, jc.ErrorIsNil)
    95  	apiCharm, err := s.uniter.Charm(sch.URL())
    96  	c.Assert(err, jc.ErrorIsNil)
    97  
    98  	surlBad, err := url.Parse(s.URL("/some/charm.bundle?bad"))
    99  	c.Assert(err, jc.ErrorIsNil)
   100  	surlGood, err := url.Parse(s.URL("/some/charm.bundle?good"))
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	mock := &mockArchiveURLCharm{
   103  		apiCharm,
   104  		[]*url.URL{surlBad, surlGood},
   105  	}
   106  	return mock, sch, bundata
   107  }
   108  
   109  type mockArchiveURLCharm struct {
   110  	charm.BundleInfo
   111  	archiveURLs []*url.URL
   112  }
   113  
   114  func (i *mockArchiveURLCharm) ArchiveURLs() ([]*url.URL, error) {
   115  	return i.archiveURLs, nil
   116  }
   117  
   118  func (s *BundlesDirSuite) TestGet(c *gc.C) {
   119  	basedir := c.MkDir()
   120  	bunsdir := filepath.Join(basedir, "random", "bundles")
   121  	d := charm.NewBundlesDir(bunsdir)
   122  
   123  	// Check it doesn't get created until it's needed.
   124  	_, err := os.Stat(bunsdir)
   125  	c.Assert(err, jc.Satisfies, os.IsNotExist)
   126  
   127  	// Add a charm to state that we can try to get.
   128  	apiCharm, sch, bundata := s.AddCharm(c)
   129  
   130  	// Try to get the charm when the content doesn't match.
   131  	gitjujutesting.Server.Response(200, nil, []byte("roflcopter"))
   132  	archiveURLs, err := apiCharm.ArchiveURLs()
   133  	c.Assert(err, gc.IsNil)
   134  	_, err = d.Read(apiCharm, nil)
   135  	prefix := regexp.QuoteMeta(fmt.Sprintf(`failed to download charm "cs:quantal/dummy-1" from %q: `, archiveURLs))
   136  	c.Assert(err, gc.ErrorMatches, prefix+fmt.Sprintf(`expected sha256 %q, got ".*"`, sch.BundleSha256()))
   137  
   138  	// Try to get a charm whose bundle doesn't exist.
   139  	gitjujutesting.Server.Responses(2, 404, nil, nil)
   140  	_, err = d.Read(apiCharm, nil)
   141  	c.Assert(err, gc.ErrorMatches, prefix+`.* 404 Not Found`)
   142  
   143  	// Get a charm whose bundle exists and whose content matches.
   144  	gitjujutesting.Server.Response(404, nil, nil)
   145  	gitjujutesting.Server.Response(200, nil, bundata)
   146  	ch, err := d.Read(apiCharm, nil)
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	assertCharm(c, ch, sch)
   149  
   150  	// Get the same charm again, without preparing a response from the server.
   151  	ch, err = d.Read(apiCharm, nil)
   152  	c.Assert(err, jc.ErrorIsNil)
   153  	assertCharm(c, ch, sch)
   154  
   155  	// Abort a download.
   156  	err = os.RemoveAll(bunsdir)
   157  	c.Assert(err, jc.ErrorIsNil)
   158  	abort := make(chan struct{})
   159  	done := make(chan bool)
   160  	go func() {
   161  		ch, err := d.Read(apiCharm, abort)
   162  		c.Assert(ch, gc.IsNil)
   163  		c.Assert(err, gc.ErrorMatches, prefix+"aborted")
   164  		close(done)
   165  	}()
   166  	close(abort)
   167  	gitjujutesting.Server.Response(500, nil, nil)
   168  	select {
   169  	case <-done:
   170  	case <-time.After(coretesting.LongWait):
   171  		c.Fatalf("timed out waiting for abort")
   172  	}
   173  }
   174  
   175  func readHash(c *gc.C, path string) ([]byte, string) {
   176  	data, err := ioutil.ReadFile(path)
   177  	c.Assert(err, jc.ErrorIsNil)
   178  	hash := sha256.New()
   179  	hash.Write(data)
   180  	return data, hex.EncodeToString(hash.Sum(nil))
   181  }
   182  
   183  func assertCharm(c *gc.C, bun charm.Bundle, sch *state.Charm) {
   184  	actual := bun.(*corecharm.CharmArchive)
   185  	c.Assert(actual.Revision(), gc.Equals, sch.Revision())
   186  	c.Assert(actual.Meta(), gc.DeepEquals, sch.Meta())
   187  	c.Assert(actual.Config(), gc.DeepEquals, sch.Config())
   188  }