github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/apicaller/retry_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apicaller_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/testing" 9 jc "github.com/juju/testing/checkers" 10 "github.com/juju/utils" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/api" 14 "github.com/juju/juju/worker/apicaller" 15 ) 16 17 // RetryStrategySuite exercises the cases where we need to connect 18 // repeatedly, either to wait for provisioning errors or to fall 19 // back to other possible passwords. It covers OnlyConnect in detail, 20 // checking success and failure behaviour, but only checks suitable 21 // error paths for ScaryConnect (which does extra complex things like 22 // make api calls and rewrite passwords in config). 23 // 24 // Would be best of all to test all the ScaryConnect success/failure 25 // paths explicitly, but the combinatorial explosion makes it tricky; 26 // in the absence of a further decomposition of responsibilities, it 27 // seems best to at least decompose the testing. Which is more detailed 28 // than it was before, anyway. 29 type RetryStrategySuite struct { 30 testing.IsolationSuite 31 } 32 33 var _ = gc.Suite(&RetryStrategySuite{}) 34 35 func (s *RetryStrategySuite) TestOnlyConnectSuccess(c *gc.C) { 36 stub := &testing.Stub{} 37 stub.SetErrors( 38 errNotProvisioned, // initial attempt, outside strategy 39 errNotProvisioned, // first strategy attempt 40 nil, // success on second strategy attempt 41 ) 42 // TODO(katco): 2016-08-09: lp:1611427 43 strategy := utils.AttemptStrategy{Min: 3} 44 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 45 return apicaller.OnlyConnect(&mockAgent{stub: stub}, apiOpen) 46 }) 47 checkOpenCalls(c, stub, "new", "new", "new") 48 c.Check(conn, gc.NotNil) 49 c.Check(err, jc.ErrorIsNil) 50 } 51 52 func (s *RetryStrategySuite) TestOnlyConnectOldPasswordSuccess(c *gc.C) { 53 stub := &testing.Stub{} 54 stub.SetErrors( 55 errNotAuthorized, // initial attempt, outside strategy 56 errNotProvisioned, // fallback attempt, outside strategy 57 errNotProvisioned, // first strategy attempt 58 nil, // second strategy attempt 59 ) 60 // TODO(katco): 2016-08-09: lp:1611427 61 strategy := utils.AttemptStrategy{Min: 3} 62 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 63 return apicaller.OnlyConnect(&mockAgent{stub: stub}, apiOpen) 64 }) 65 checkOpenCalls(c, stub, "new", "old", "old", "old") 66 c.Check(err, jc.ErrorIsNil) 67 c.Check(conn, gc.NotNil) 68 } 69 70 func (s *RetryStrategySuite) TestOnlyConnectEventualError(c *gc.C) { 71 conn, err := checkWaitProvisionedError(c, apicaller.OnlyConnect) 72 c.Check(conn, gc.IsNil) 73 c.Check(err, gc.ErrorMatches, "splat pow") 74 } 75 76 func (s *RetryStrategySuite) TestScaryConnectEventualError(c *gc.C) { 77 conn, err := checkWaitProvisionedError(c, apicaller.ScaryConnect) 78 c.Check(conn, gc.IsNil) 79 c.Check(err, gc.ErrorMatches, "splat pow") 80 } 81 82 func checkWaitProvisionedError(c *gc.C, connect apicaller.ConnectFunc) (api.Connection, error) { 83 stub := &testing.Stub{} 84 stub.SetErrors( 85 errNotProvisioned, // initial attempt, outside strategy 86 errNotProvisioned, // first strategy attempt 87 errNotProvisioned, // second strategy attempt 88 errors.New("splat pow"), // third strategy attempt 89 ) 90 // TODO(katco): 2016-08-09: lp:1611427 91 strategy := utils.AttemptStrategy{Min: 3} 92 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 93 return connect(&mockAgent{stub: stub}, apiOpen) 94 }) 95 checkOpenCalls(c, stub, "new", "new", "new", "new") 96 return conn, err 97 } 98 99 func (s *RetryStrategySuite) TestOnlyConnectNeverProvisioned(c *gc.C) { 100 conn, err := checkWaitNeverProvisioned(c, apicaller.OnlyConnect) 101 c.Check(conn, gc.IsNil) 102 c.Check(errors.Cause(err), gc.DeepEquals, errNotProvisioned) 103 } 104 105 func (s *RetryStrategySuite) TestScaryConnectNeverProvisioned(c *gc.C) { 106 conn, err := checkWaitNeverProvisioned(c, apicaller.ScaryConnect) 107 c.Check(conn, gc.IsNil) 108 c.Check(err, gc.Equals, apicaller.ErrConnectImpossible) 109 } 110 111 func checkWaitNeverProvisioned(c *gc.C, connect apicaller.ConnectFunc) (api.Connection, error) { 112 stub := &testing.Stub{} 113 stub.SetErrors( 114 errNotProvisioned, // initial attempt, outside strategy 115 errNotProvisioned, // first strategy attempt 116 errNotProvisioned, // second strategy attempt 117 errNotProvisioned, // third strategy attempt 118 ) 119 // TODO(katco): 2016-08-09: lp:1611427 120 strategy := utils.AttemptStrategy{Min: 3} 121 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 122 return connect(&mockAgent{stub: stub}, apiOpen) 123 }) 124 checkOpenCalls(c, stub, "new", "new", "new", "new") 125 return conn, err 126 }