github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 strategy := utils.AttemptStrategy{Min: 3} 43 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 44 return apicaller.OnlyConnect(&mockAgent{stub: stub}, apiOpen) 45 }) 46 checkOpenCalls(c, stub, "new", "new", "new") 47 c.Check(conn, gc.NotNil) 48 c.Check(err, jc.ErrorIsNil) 49 } 50 51 func (s *RetryStrategySuite) TestOnlyConnectOldPasswordSuccess(c *gc.C) { 52 stub := &testing.Stub{} 53 stub.SetErrors( 54 errNotAuthorized, // initial attempt, outside strategy 55 errNotProvisioned, // fallback attempt, outside strategy 56 errNotProvisioned, // first strategy attempt 57 nil, // second strategy attempt 58 ) 59 strategy := utils.AttemptStrategy{Min: 3} 60 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 61 return apicaller.OnlyConnect(&mockAgent{stub: stub}, apiOpen) 62 }) 63 checkOpenCalls(c, stub, "new", "old", "old", "old") 64 c.Check(err, jc.ErrorIsNil) 65 c.Check(conn, gc.NotNil) 66 } 67 68 func (s *RetryStrategySuite) TestOnlyConnectEventualError(c *gc.C) { 69 conn, err := checkWaitProvisionedError(c, apicaller.OnlyConnect) 70 c.Check(conn, gc.IsNil) 71 c.Check(err, gc.ErrorMatches, "splat pow") 72 } 73 74 func (s *RetryStrategySuite) TestScaryConnectEventualError(c *gc.C) { 75 conn, err := checkWaitProvisionedError(c, apicaller.ScaryConnect) 76 c.Check(conn, gc.IsNil) 77 c.Check(err, gc.ErrorMatches, "splat pow") 78 } 79 80 func checkWaitProvisionedError(c *gc.C, connect apicaller.ConnectFunc) (api.Connection, error) { 81 stub := &testing.Stub{} 82 stub.SetErrors( 83 errNotProvisioned, // initial attempt, outside strategy 84 errNotProvisioned, // first strategy attempt 85 errNotProvisioned, // second strategy attempt 86 errors.New("splat pow"), // third strategy attempt 87 ) 88 strategy := utils.AttemptStrategy{Min: 3} 89 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 90 return connect(&mockAgent{stub: stub}, apiOpen) 91 }) 92 checkOpenCalls(c, stub, "new", "new", "new", "new") 93 return conn, err 94 } 95 96 func (s *RetryStrategySuite) TestOnlyConnectNeverProvisioned(c *gc.C) { 97 conn, err := checkWaitNeverProvisioned(c, apicaller.OnlyConnect) 98 c.Check(conn, gc.IsNil) 99 c.Check(errors.Cause(err), gc.DeepEquals, errNotProvisioned) 100 } 101 102 func (s *RetryStrategySuite) TestScaryConnectNeverProvisioned(c *gc.C) { 103 conn, err := checkWaitNeverProvisioned(c, apicaller.ScaryConnect) 104 c.Check(conn, gc.IsNil) 105 c.Check(err, gc.Equals, apicaller.ErrConnectImpossible) 106 } 107 108 func checkWaitNeverProvisioned(c *gc.C, connect apicaller.ConnectFunc) (api.Connection, error) { 109 stub := &testing.Stub{} 110 stub.SetErrors( 111 errNotProvisioned, // initial attempt, outside strategy 112 errNotProvisioned, // first strategy attempt 113 errNotProvisioned, // second strategy attempt 114 errNotProvisioned, // third strategy attempt 115 ) 116 strategy := utils.AttemptStrategy{Min: 3} 117 conn, err := strategyTest(stub, strategy, func(apiOpen api.OpenFunc) (api.Connection, error) { 118 return connect(&mockAgent{stub: stub}, apiOpen) 119 }) 120 checkOpenCalls(c, stub, "new", "new", "new", "new") 121 return conn, err 122 }