github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/common/controller_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 5 6 import ( 7 "io" 8 "time" 9 10 "github.com/juju/cmd" 11 "github.com/juju/cmd/cmdtesting" 12 "github.com/juju/errors" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/api" 17 "github.com/juju/juju/apiserver/params" 18 jujucmd "github.com/juju/juju/cmd" 19 "github.com/juju/juju/cmd/modelcmd" 20 "github.com/juju/juju/jujuclient/jujuclienttesting" 21 "github.com/juju/juju/rpc" 22 "github.com/juju/juju/testing" 23 "github.com/juju/juju/version" 24 ) 25 26 var _ = gc.Suite(&controllerSuite{}) 27 28 type controllerSuite struct { 29 testing.BaseSuite 30 mockBlockClient *mockBlockClient 31 } 32 33 func (s *controllerSuite) SetUpTest(c *gc.C) { 34 s.mockBlockClient = &mockBlockClient{} 35 s.PatchValue(&blockAPI, func(*modelcmd.ModelCommandBase) (listBlocksAPI, error) { 36 err := s.mockBlockClient.loginError 37 if err != nil { 38 s.mockBlockClient.loginError = nil 39 return nil, err 40 } 41 if s.mockBlockClient.discoveringSpacesError > 0 { 42 s.mockBlockClient.discoveringSpacesError -= 1 43 return nil, errors.New("spaces are still being discovered") 44 } 45 return s.mockBlockClient, nil 46 }) 47 } 48 49 type mockBlockClient struct { 50 retryCount int 51 numRetries int 52 discoveringSpacesError int 53 loginError error 54 } 55 56 var errOther = errors.New("other error") 57 58 func (c *mockBlockClient) List() ([]params.Block, error) { 59 c.retryCount += 1 60 if c.retryCount == 5 { 61 return nil, &rpc.RequestError{Message: params.CodeUpgradeInProgress, Code: params.CodeUpgradeInProgress} 62 } 63 if c.numRetries < 0 { 64 return nil, errOther 65 } 66 if c.retryCount < c.numRetries { 67 return nil, &rpc.RequestError{Message: params.CodeUpgradeInProgress, Code: params.CodeUpgradeInProgress} 68 } 69 return []params.Block{}, nil 70 } 71 72 func (c *mockBlockClient) Close() error { 73 return nil 74 } 75 76 func (s *controllerSuite) TestWaitForAgentAPIReadyRetries(c *gc.C) { 77 s.PatchValue(&bootstrapReadyPollDelay, 1*time.Millisecond) 78 s.PatchValue(&bootstrapReadyPollCount, 5) 79 defaultSeriesVersion := version.Current 80 // Force a dev version by having a non zero build number. 81 // This is because we have not uploaded any tools and auto 82 // upload is only enabled for dev versions. 83 defaultSeriesVersion.Build = 1234 84 s.PatchValue(&version.Current, defaultSeriesVersion) 85 for _, t := range []struct { 86 numRetries int 87 err error 88 }{ 89 {0, nil}, // agent ready immediately 90 {2, nil}, // agent ready after 2 polls 91 {6, &rpc.RequestError{ 92 Message: params.CodeUpgradeInProgress, 93 Code: params.CodeUpgradeInProgress, 94 }}, // agent ready after 6 polls but that's too long 95 {-1, errOther}, // another error is returned 96 } { 97 s.mockBlockClient.numRetries = t.numRetries 98 s.mockBlockClient.retryCount = 0 99 runInCommand(c, func(ctx *cmd.Context, base *modelcmd.ModelCommandBase) { 100 err := WaitForAgentInitialisation(ctx, base, "controller", "default") 101 c.Check(errors.Cause(err), gc.DeepEquals, t.err) 102 }) 103 expectedRetries := t.numRetries 104 if t.numRetries <= 0 { 105 expectedRetries = 1 106 } 107 // Only retry maximum of bootstrapReadyPollCount times. 108 if expectedRetries > 5 { 109 expectedRetries = 5 110 } 111 c.Check(s.mockBlockClient.retryCount, gc.Equals, expectedRetries) 112 } 113 } 114 115 func (s *controllerSuite) TestWaitForAgentAPIReadyWaitsForSpaceDiscovery(c *gc.C) { 116 s.mockBlockClient.discoveringSpacesError = 2 117 118 runInCommand(c, func(ctx *cmd.Context, base *modelcmd.ModelCommandBase) { 119 err := WaitForAgentInitialisation(ctx, base, "controller", "default") 120 c.Check(err, jc.ErrorIsNil) 121 }) 122 c.Assert(s.mockBlockClient.discoveringSpacesError, gc.Equals, 0) 123 } 124 125 func (s *controllerSuite) TestWaitForAgentAPIReadyRetriesWithOpenEOFErr(c *gc.C) { 126 s.mockBlockClient.numRetries = 0 127 s.mockBlockClient.retryCount = 0 128 s.mockBlockClient.loginError = io.EOF 129 130 runInCommand(c, func(ctx *cmd.Context, base *modelcmd.ModelCommandBase) { 131 err := WaitForAgentInitialisation(ctx, base, "controller", "default") 132 c.Check(err, jc.ErrorIsNil) 133 }) 134 c.Check(s.mockBlockClient.retryCount, gc.Equals, 1) 135 } 136 137 func (s *controllerSuite) TestWaitForAgentAPIReadyStopsRetriesWithOpenErr(c *gc.C) { 138 s.mockBlockClient.numRetries = 0 139 s.mockBlockClient.retryCount = 0 140 s.mockBlockClient.loginError = errors.NewUnauthorized(nil, "") 141 runInCommand(c, func(ctx *cmd.Context, base *modelcmd.ModelCommandBase) { 142 err := WaitForAgentInitialisation(ctx, base, "controller", "default") 143 c.Check(err, jc.Satisfies, errors.IsUnauthorized) 144 }) 145 c.Check(s.mockBlockClient.retryCount, gc.Equals, 0) 146 } 147 148 func runInCommand(c *gc.C, run func(ctx *cmd.Context, base *modelcmd.ModelCommandBase)) { 149 cmd := &testCommand{ 150 run: run, 151 } 152 cmd.SetClientStore(jujuclienttesting.MinimalStore()) 153 cmd.SetAPIOpen(func(*api.Info, api.DialOpts) (api.Connection, error) { 154 return nil, errors.New("no API available") 155 }) 156 157 _, err := cmdtesting.RunCommand(c, modelcmd.Wrap(cmd)) 158 c.Assert(err, jc.ErrorIsNil) 159 } 160 161 type testCommand struct { 162 modelcmd.ModelCommandBase 163 run func(ctx *cmd.Context, base *modelcmd.ModelCommandBase) 164 } 165 166 func (c *testCommand) Run(ctx *cmd.Context) error { 167 c.run(ctx, &c.ModelCommandBase) 168 return nil 169 } 170 171 func (c *testCommand) Info() *cmd.Info { 172 return jujucmd.Info(&cmd.Info{ 173 Name: "test", 174 }) 175 }