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 }