github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/controller/charmrevisionupdater/updater_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package charmrevisionupdater_test 5 6 import ( 7 "net/http" 8 "net/http/httptest" 9 10 "github.com/juju/errors" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 "gopkg.in/juju/charm.v6" 14 "gopkg.in/juju/charmrepo.v3" 15 "gopkg.in/juju/names.v2" 16 17 "github.com/juju/juju/apiserver/common" 18 "github.com/juju/juju/apiserver/facades/controller/charmrevisionupdater" 19 "github.com/juju/juju/apiserver/facades/controller/charmrevisionupdater/testing" 20 apiservertesting "github.com/juju/juju/apiserver/testing" 21 "github.com/juju/juju/charmstore" 22 jujutesting "github.com/juju/juju/juju/testing" 23 "github.com/juju/juju/state" 24 "github.com/juju/juju/version" 25 ) 26 27 type charmVersionSuite struct { 28 testing.CharmSuite 29 jujutesting.JujuConnSuite 30 31 charmrevisionupdater *charmrevisionupdater.CharmRevisionUpdaterAPI 32 resources *common.Resources 33 authoriser apiservertesting.FakeAuthorizer 34 } 35 36 var _ = gc.Suite(&charmVersionSuite{}) 37 38 func (s *charmVersionSuite) SetUpSuite(c *gc.C) { 39 s.JujuConnSuite.SetUpSuite(c) 40 s.CharmSuite.SetUpSuite(c, &s.JujuConnSuite) 41 } 42 43 func (s *charmVersionSuite) TearDownSuite(c *gc.C) { 44 s.CharmSuite.TearDownSuite(c) 45 s.JujuConnSuite.TearDownSuite(c) 46 } 47 48 func (s *charmVersionSuite) SetUpTest(c *gc.C) { 49 s.JujuConnSuite.SetUpTest(c) 50 s.CharmSuite.SetUpTest(c) 51 s.resources = common.NewResources() 52 s.AddCleanup(func(_ *gc.C) { s.resources.StopAll() }) 53 s.authoriser = apiservertesting.FakeAuthorizer{ 54 Controller: true, 55 Tag: names.NewMachineTag("99"), 56 } 57 var err error 58 s.charmrevisionupdater, err = charmrevisionupdater.NewCharmRevisionUpdaterAPI(s.State, s.resources, s.authoriser) 59 c.Assert(err, jc.ErrorIsNil) 60 } 61 62 func (s *charmVersionSuite) TearDownTest(c *gc.C) { 63 s.CharmSuite.TearDownTest(c) 64 s.JujuConnSuite.TearDownTest(c) 65 } 66 67 func (s *charmVersionSuite) TestNewCharmRevisionUpdaterAPIAcceptsStateManager(c *gc.C) { 68 endPoint, err := charmrevisionupdater.NewCharmRevisionUpdaterAPI(s.State, s.resources, s.authoriser) 69 c.Assert(err, jc.ErrorIsNil) 70 c.Assert(endPoint, gc.NotNil) 71 } 72 73 func (s *charmVersionSuite) TestNewCharmRevisionUpdaterAPIRefusesNonStateManager(c *gc.C) { 74 anAuthoriser := s.authoriser 75 anAuthoriser.Controller = false 76 endPoint, err := charmrevisionupdater.NewCharmRevisionUpdaterAPI(s.State, s.resources, anAuthoriser) 77 c.Assert(endPoint, gc.IsNil) 78 c.Assert(err, gc.ErrorMatches, "permission denied") 79 } 80 81 func (s *charmVersionSuite) TestUpdateRevisions(c *gc.C) { 82 s.AddMachine(c, "0", state.JobManageModel) 83 s.SetupScenario(c) 84 85 curl := charm.MustParseURL("cs:quantal/mysql") 86 _, err := s.State.LatestPlaceholderCharm(curl) 87 c.Assert(err, jc.Satisfies, errors.IsNotFound) 88 89 curl = charm.MustParseURL("cs:quantal/wordpress") 90 _, err = s.State.LatestPlaceholderCharm(curl) 91 c.Assert(err, jc.Satisfies, errors.IsNotFound) 92 93 result, err := s.charmrevisionupdater.UpdateLatestRevisions() 94 c.Assert(err, jc.ErrorIsNil) 95 c.Assert(result.Error, gc.IsNil) 96 97 curl = charm.MustParseURL("cs:quantal/mysql") 98 pending, err := s.State.LatestPlaceholderCharm(curl) 99 c.Assert(err, jc.ErrorIsNil) 100 c.Assert(pending.String(), gc.Equals, "cs:quantal/mysql-23") 101 102 // Latest wordpress is already deployed, so no pending charm. 103 curl = charm.MustParseURL("cs:quantal/wordpress") 104 _, err = s.State.LatestPlaceholderCharm(curl) 105 c.Assert(err, jc.Satisfies, errors.IsNotFound) 106 107 // Varnish has an error when updating, so no pending charm. 108 curl = charm.MustParseURL("cs:quantal/varnish") 109 _, err = s.State.LatestPlaceholderCharm(curl) 110 c.Assert(err, jc.Satisfies, errors.IsNotFound) 111 112 // Update mysql version and run update again. 113 app, err := s.State.Application("mysql") 114 c.Assert(err, jc.ErrorIsNil) 115 ch := s.AddCharmWithRevision(c, "mysql", 23) 116 cfg := state.SetCharmConfig{ 117 Charm: ch, 118 ForceUnits: true, 119 } 120 err = app.SetCharm(cfg) 121 c.Assert(err, jc.ErrorIsNil) 122 123 result, err = s.charmrevisionupdater.UpdateLatestRevisions() 124 c.Assert(err, jc.ErrorIsNil) 125 c.Assert(result.Error, gc.IsNil) 126 127 // Latest mysql is now deployed, so no pending charm. 128 curl = charm.MustParseURL("cs:quantal/mysql") 129 _, err = s.State.LatestPlaceholderCharm(curl) 130 c.Assert(err, jc.Satisfies, errors.IsNotFound) 131 } 132 133 func (s *charmVersionSuite) TestWordpressCharmNoReadAccessIsNotVisible(c *gc.C) { 134 s.AddMachine(c, "0", state.JobManageModel) 135 s.SetupScenario(c) 136 137 // Disallow read access to the wordpress charm in the charm store. 138 err := s.Client.Put("/quantal/wordpress/meta/perm/read", nil) 139 c.Assert(err, jc.ErrorIsNil) 140 141 // Run the revision updater and check that the public charm updates are 142 // still properly notified. 143 result, err := s.charmrevisionupdater.UpdateLatestRevisions() 144 c.Assert(err, jc.ErrorIsNil) 145 c.Assert(result.Error, gc.IsNil) 146 147 curl := charm.MustParseURL("cs:quantal/mysql") 148 pending, err := s.State.LatestPlaceholderCharm(curl) 149 c.Assert(err, jc.ErrorIsNil) 150 c.Assert(pending.String(), gc.Equals, "cs:quantal/mysql-23") 151 152 // No pending charm for wordpress. 153 curl = charm.MustParseURL("cs:quantal/wordpress") 154 _, err = s.State.LatestPlaceholderCharm(curl) 155 c.Assert(err, jc.Satisfies, errors.IsNotFound) 156 } 157 158 func (s *charmVersionSuite) TestJujuMetadataHeaderIsSent(c *gc.C) { 159 s.AddMachine(c, "0", state.JobManageModel) 160 s.SetupScenario(c) 161 162 // Set up a charm store server that stores the request header. 163 var header http.Header 164 received := false 165 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 166 // the first request is the one with the UUID. 167 if !received { 168 header = r.Header 169 received = true 170 } 171 s.Handler.ServeHTTP(w, r) 172 })) 173 defer srv.Close() 174 175 // Point the charm repo initializer to the testing server. 176 s.PatchValue(&charmrevisionupdater.NewCharmStoreClient, func(st *state.State) (charmstore.Client, error) { 177 return charmstore.NewCachingClient(state.MacaroonCache{st}, srv.URL) 178 }) 179 180 result, err := s.charmrevisionupdater.UpdateLatestRevisions() 181 c.Assert(err, jc.ErrorIsNil) 182 c.Assert(result.Error, gc.IsNil) 183 184 model, err := s.State.Model() 185 c.Assert(err, jc.ErrorIsNil) 186 cloud, err := s.State.Cloud(model.Cloud()) 187 c.Assert(err, jc.ErrorIsNil) 188 expectedHeader := []string{ 189 "arch=amd64", // This is the architecture of the deployed applications. 190 "cloud=" + model.Cloud(), 191 "cloud_region=" + model.CloudRegion(), 192 "controller_uuid=" + s.State.ControllerUUID(), 193 "controller_version=" + version.Current.String(), 194 "environment_uuid=" + model.UUID(), 195 "is_controller=true", 196 "model_uuid=" + model.UUID(), 197 "provider=" + cloud.Type, 198 "series=quantal", 199 } 200 for i, expected := range expectedHeader { 201 c.Assert(header[charmrepo.JujuMetadataHTTPHeader][i], gc.Equals, expected) 202 } 203 }