github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/romulus/setplan/set_plan_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package setplan_test 5 6 import ( 7 "encoding/json" 8 "fmt" 9 "net/url" 10 stdtesting "testing" 11 12 "github.com/juju/cmd/cmdtesting" 13 "github.com/juju/errors" 14 "github.com/juju/testing" 15 jc "github.com/juju/testing/checkers" 16 gc "gopkg.in/check.v1" 17 "gopkg.in/juju/charm.v6" 18 "gopkg.in/macaroon-bakery.v2-unstable/bakery" 19 "gopkg.in/macaroon-bakery.v2-unstable/bakery/checkers" 20 "gopkg.in/macaroon.v2-unstable" 21 22 rcmd "github.com/juju/juju/cmd/juju/romulus" 23 "github.com/juju/juju/cmd/juju/romulus/setplan" 24 "github.com/juju/juju/cmd/modelcmd" 25 jjjtesting "github.com/juju/juju/juju/testing" 26 "github.com/juju/juju/state" 27 "github.com/juju/juju/testcharms" 28 jjtesting "github.com/juju/juju/testing" 29 ) 30 31 func TestPackage(t *stdtesting.T) { 32 jjtesting.MgoTestPackage(t) 33 } 34 35 var _ = gc.Suite(&setPlanCommandSuite{}) 36 37 type setPlanCommandSuite struct { 38 jjjtesting.JujuConnSuite 39 40 mockAPI *mockapi 41 charmURL string 42 } 43 44 func (s *setPlanCommandSuite) SetUpTest(c *gc.C) { 45 s.JujuConnSuite.SetUpTest(c) 46 47 ch := testcharms.Repo.CharmDir("dummy") 48 curl := charm.MustParseURL( 49 fmt.Sprintf("local:quantal/%s-%d", ch.Meta().Name, ch.Revision()), 50 ) 51 s.charmURL = curl.String() 52 charmInfo := state.CharmInfo{ 53 Charm: ch, 54 ID: curl, 55 StoragePath: "dummy-path", 56 SHA256: "dummy-1", 57 } 58 dummyCharm, err := s.State.AddCharm(charmInfo) 59 c.Assert(err, jc.ErrorIsNil) 60 s.AddTestingApplication(c, "mysql", dummyCharm) 61 62 mockAPI, err := newMockAPI() 63 c.Assert(err, jc.ErrorIsNil) 64 s.mockAPI = mockAPI 65 66 s.PatchValue(setplan.NewAuthorizationClient, setplan.APIClientFnc(s.mockAPI)) 67 s.PatchValue(&rcmd.GetMeteringURLForModelCmd, func(c *modelcmd.ModelCommandBase) (string, error) { 68 return "http://example.com", nil 69 }) 70 } 71 72 func (s setPlanCommandSuite) TestSetPlanCommand(c *gc.C) { 73 tests := []struct { 74 about string 75 plan string 76 application string 77 err string 78 apiErr error 79 apiCalls []testing.StubCall 80 }{{ 81 about: "all is well", 82 plan: "bob/default", 83 application: "mysql", 84 apiCalls: []testing.StubCall{{ 85 FuncName: "Authorize", 86 Args: []interface{}{ 87 s.State.ModelUUID(), 88 s.charmURL, 89 "mysql", 90 }, 91 }}, 92 }, { 93 about: "invalid application name", 94 plan: "bob/default", 95 application: "mysql-0", 96 err: "invalid application name \"mysql-0\"", 97 }, { 98 about: "unknown application", 99 plan: "bob/default", 100 application: "wordpress", 101 err: "application \"wordpress\" not found.*", 102 }, { 103 about: "unknown application", 104 plan: "bob/default", 105 application: "mysql", 106 apiErr: errors.New("some strange error"), 107 err: "some strange error", 108 }, 109 } 110 for i, test := range tests { 111 c.Logf("running test %d: %v", i, test.about) 112 s.mockAPI.ResetCalls() 113 if test.apiErr != nil { 114 s.mockAPI.SetErrors(test.apiErr) 115 } 116 _, err := cmdtesting.RunCommand(c, setplan.NewSetPlanCommand(), test.application, test.plan) 117 if test.err == "" { 118 c.Assert(err, jc.ErrorIsNil) 119 c.Assert(s.mockAPI.Calls(), gc.HasLen, 1) 120 s.mockAPI.CheckCalls(c, test.apiCalls) 121 122 app, err := s.State.Application("mysql") 123 c.Assert(err, jc.ErrorIsNil) 124 svcMacaroon := app.MetricCredentials() 125 data, err := json.Marshal(macaroon.Slice{s.mockAPI.macaroon}) 126 c.Assert(err, jc.ErrorIsNil) 127 c.Assert(svcMacaroon, gc.DeepEquals, data) 128 } else { 129 c.Assert(err, gc.ErrorMatches, test.err) 130 c.Assert(s.mockAPI.Calls(), gc.HasLen, 0) 131 } 132 } 133 } 134 135 func (s *setPlanCommandSuite) TestNoArgs(c *gc.C) { 136 _, err := cmdtesting.RunCommand(c, setplan.NewSetPlanCommand()) 137 c.Assert(err, gc.ErrorMatches, "need to specify application name and plan url") 138 } 139 140 func newMockAPI() (*mockapi, error) { 141 kp, err := bakery.GenerateKey() 142 if err != nil { 143 return nil, errors.Trace(err) 144 } 145 svc, err := bakery.NewService(bakery.NewServiceParams{ 146 Location: "omnibus", 147 Key: kp, 148 }) 149 if err != nil { 150 return nil, errors.Trace(err) 151 } 152 return &mockapi{ 153 service: svc, 154 }, nil 155 } 156 157 type mockapi struct { 158 testing.Stub 159 160 service *bakery.Service 161 macaroon *macaroon.Macaroon 162 } 163 164 func (m *mockapi) Authorize(modelUUID, charmURL, applicationName, plan string, visitWebPage func(*url.URL) error) (*macaroon.Macaroon, error) { 165 err := m.NextErr() 166 if err != nil { 167 return nil, errors.Trace(err) 168 } 169 m.AddCall("Authorize", modelUUID, charmURL, applicationName) 170 macaroon, err := m.service.NewMacaroon( 171 172 []checkers.Caveat{ 173 checkers.DeclaredCaveat("environment", modelUUID), 174 checkers.DeclaredCaveat("charm", charmURL), 175 checkers.DeclaredCaveat("service", applicationName), 176 checkers.DeclaredCaveat("plan", plan), 177 }) 178 179 if err != nil { 180 return nil, errors.Trace(err) 181 } 182 m.macaroon = macaroon 183 return m.macaroon, nil 184 }