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  }