github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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 sch, err := s.State.AddCharm(bun, curl, storagePath, hash) 88 c.Assert(err, jc.ErrorIsNil) 89 apiCharm, err := s.uniter.Charm(sch.URL()) 90 c.Assert(err, jc.ErrorIsNil) 91 92 surlBad, err := url.Parse(s.URL("/some/charm.bundle?bad")) 93 c.Assert(err, jc.ErrorIsNil) 94 surlGood, err := url.Parse(s.URL("/some/charm.bundle?good")) 95 c.Assert(err, jc.ErrorIsNil) 96 mock := &mockArchiveURLCharm{ 97 apiCharm, 98 []*url.URL{surlBad, surlGood}, 99 } 100 return mock, sch, bundata 101 } 102 103 type mockArchiveURLCharm struct { 104 charm.BundleInfo 105 archiveURLs []*url.URL 106 } 107 108 func (i *mockArchiveURLCharm) ArchiveURLs() ([]*url.URL, error) { 109 return i.archiveURLs, nil 110 } 111 112 func (s *BundlesDirSuite) TestGet(c *gc.C) { 113 basedir := c.MkDir() 114 bunsdir := filepath.Join(basedir, "random", "bundles") 115 d := charm.NewBundlesDir(bunsdir) 116 117 // Check it doesn't get created until it's needed. 118 _, err := os.Stat(bunsdir) 119 c.Assert(err, jc.Satisfies, os.IsNotExist) 120 121 // Add a charm to state that we can try to get. 122 apiCharm, sch, bundata := s.AddCharm(c) 123 124 // Try to get the charm when the content doesn't match. 125 gitjujutesting.Server.Response(200, nil, []byte("roflcopter")) 126 archiveURLs, err := apiCharm.ArchiveURLs() 127 c.Assert(err, gc.IsNil) 128 _, err = d.Read(apiCharm, nil) 129 prefix := regexp.QuoteMeta(fmt.Sprintf(`failed to download charm "cs:quantal/dummy-1" from %q: `, archiveURLs)) 130 c.Assert(err, gc.ErrorMatches, prefix+fmt.Sprintf(`expected sha256 %q, got ".*"`, sch.BundleSha256())) 131 132 // Try to get a charm whose bundle doesn't exist. 133 gitjujutesting.Server.Responses(2, 404, nil, nil) 134 _, err = d.Read(apiCharm, nil) 135 c.Assert(err, gc.ErrorMatches, prefix+`.* 404 Not Found`) 136 137 // Get a charm whose bundle exists and whose content matches. 138 gitjujutesting.Server.Response(404, nil, nil) 139 gitjujutesting.Server.Response(200, nil, bundata) 140 ch, err := d.Read(apiCharm, nil) 141 c.Assert(err, jc.ErrorIsNil) 142 assertCharm(c, ch, sch) 143 144 // Get the same charm again, without preparing a response from the server. 145 ch, err = d.Read(apiCharm, nil) 146 c.Assert(err, jc.ErrorIsNil) 147 assertCharm(c, ch, sch) 148 149 // Abort a download. 150 err = os.RemoveAll(bunsdir) 151 c.Assert(err, jc.ErrorIsNil) 152 abort := make(chan struct{}) 153 done := make(chan bool) 154 go func() { 155 ch, err := d.Read(apiCharm, abort) 156 c.Assert(ch, gc.IsNil) 157 c.Assert(err, gc.ErrorMatches, prefix+"aborted") 158 close(done) 159 }() 160 close(abort) 161 gitjujutesting.Server.Response(500, nil, nil) 162 select { 163 case <-done: 164 case <-time.After(coretesting.LongWait): 165 c.Fatalf("timed out waiting for abort") 166 } 167 } 168 169 func readHash(c *gc.C, path string) ([]byte, string) { 170 data, err := ioutil.ReadFile(path) 171 c.Assert(err, jc.ErrorIsNil) 172 hash := sha256.New() 173 hash.Write(data) 174 return data, hex.EncodeToString(hash.Sum(nil)) 175 } 176 177 func assertCharm(c *gc.C, bun charm.Bundle, sch *state.Charm) { 178 actual := bun.(*corecharm.CharmArchive) 179 c.Assert(actual.Revision(), gc.Equals, sch.Revision()) 180 c.Assert(actual.Meta(), gc.DeepEquals, sch.Meta()) 181 c.Assert(actual.Config(), gc.DeepEquals, sch.Config()) 182 }