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