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  }