github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/api/base/testing/apicaller.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package testing
     5  
     6  import (
     7  	"net/url"
     8  
     9  	"github.com/juju/errors"
    10  	"github.com/juju/httprequest"
    11  	"github.com/juju/names"
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	gc "gopkg.in/check.v1"
    15  
    16  	"github.com/juju/juju/api/base"
    17  	coretesting "github.com/juju/juju/testing"
    18  )
    19  
    20  // APICallerFunc is a function type that implements APICaller.
    21  // The only method that actually does anything is APICall itself
    22  // which calls the function. The other methods are just stubs.
    23  type APICallerFunc func(objType string, version int, id, request string, params, response interface{}) error
    24  
    25  func (f APICallerFunc) APICall(objType string, version int, id, request string, params, response interface{}) error {
    26  	return f(objType, version, id, request, params, response)
    27  }
    28  
    29  func (APICallerFunc) BestFacadeVersion(facade string) int {
    30  	// TODO(fwereade): this should return something arbitrary (e.g. 37)
    31  	// so that it can't be confused with mere uninitialized data.
    32  	return 0
    33  }
    34  
    35  func (APICallerFunc) ModelTag() (names.ModelTag, error) {
    36  	return coretesting.ModelTag, nil
    37  }
    38  
    39  func (APICallerFunc) Close() error {
    40  	return nil
    41  }
    42  
    43  func (APICallerFunc) HTTPClient() (*httprequest.Client, error) {
    44  	return nil, errors.New("no HTTP client available in this test")
    45  }
    46  
    47  func (APICallerFunc) ConnectStream(path string, attrs url.Values) (base.Stream, error) {
    48  	return nil, errors.New("stream connection unimplemented")
    49  }
    50  
    51  // CheckArgs holds the possible arguments to CheckingAPICaller(). Any
    52  // fields non empty fields will be checked to match the arguments
    53  // recieved by the APICall() method of the returned APICallerFunc. If
    54  // Id is empty, but IdIsEmpty is true, the id argument is checked to
    55  // be empty. The same applies to Version being empty, but if
    56  // VersionIsZero set to true the version is checked to be 0.
    57  type CheckArgs struct {
    58  	Facade  string
    59  	Version int
    60  	Id      string
    61  	Method  string
    62  	Args    interface{}
    63  	Results interface{}
    64  
    65  	IdIsEmpty     bool
    66  	VersionIsZero bool
    67  }
    68  
    69  func checkArgs(c *gc.C, args *CheckArgs, facade string, version int, id, method string, inArgs, outResults interface{}) {
    70  	if args == nil {
    71  		c.Logf("checkArgs: args is nil!")
    72  		return
    73  	} else {
    74  		if args.Facade != "" {
    75  			c.Check(facade, gc.Equals, args.Facade)
    76  		}
    77  		if args.Version != 0 {
    78  			c.Check(version, gc.Equals, args.Version)
    79  		} else if args.VersionIsZero {
    80  			c.Check(version, gc.Equals, 0)
    81  		}
    82  		if args.Id != "" {
    83  			c.Check(id, gc.Equals, args.Id)
    84  		} else if args.IdIsEmpty {
    85  			c.Check(id, gc.Equals, "")
    86  		}
    87  		if args.Method != "" {
    88  			c.Check(method, gc.Equals, args.Method)
    89  		}
    90  		if args.Args != nil {
    91  			c.Check(inArgs, jc.DeepEquals, args.Args)
    92  		}
    93  		if args.Results != nil {
    94  			c.Check(outResults, gc.NotNil)
    95  			testing.PatchValue(outResults, args.Results)
    96  		}
    97  	}
    98  }
    99  
   100  // CheckingAPICaller returns an APICallerFunc which can report the
   101  // number of times its APICall() method was called (if numCalls is not
   102  // nil), as well as check if any of the arguments passed to the
   103  // APICall() method match the values given in args (if args itself is
   104  // not nil, otherwise no arguments are checked). The final error
   105  // result of the APICall() will be set to err.
   106  func CheckingAPICaller(c *gc.C, args *CheckArgs, numCalls *int, err error) base.APICallCloser {
   107  	return APICallerFunc(
   108  		func(facade string, version int, id, method string, inArgs, outResults interface{}) error {
   109  			if numCalls != nil {
   110  				*numCalls++
   111  			}
   112  			if args != nil {
   113  				checkArgs(c, args, facade, version, id, method, inArgs, outResults)
   114  			}
   115  			return err
   116  		},
   117  	)
   118  }
   119  
   120  // NotifyingCheckingAPICaller returns an APICallerFunc which sends a message on the channel "called" every
   121  // time it recives a call, as well as check if any of the arguments passed to the APICall() method match
   122  // the values given in args (if args itself is not nil, otherwise no arguments are checked). The final
   123  // error result of the APICall() will be set to err.
   124  func NotifyingCheckingAPICaller(c *gc.C, args *CheckArgs, called chan struct{}, err error) base.APICaller {
   125  	return APICallerFunc(
   126  		func(facade string, version int, id, method string, inArgs, outResults interface{}) error {
   127  			called <- struct{}{}
   128  			if args != nil {
   129  				checkArgs(c, args, facade, version, id, method, inArgs, outResults)
   130  			}
   131  			return err
   132  		},
   133  	)
   134  }
   135  
   136  // CheckingAPICallerMultiArgs checks each call against the indexed expected argument. Once expected
   137  // arguments run out it doesn't check them. This is useful if your test continues to make calls after
   138  // you have checked the ones you care about.
   139  func CheckingAPICallerMultiArgs(c *gc.C, args []CheckArgs, numCalls *int, err error) base.APICallCloser {
   140  	if numCalls == nil {
   141  		panic("numCalls must be non-nill")
   142  	}
   143  	return APICallerFunc(
   144  		func(facade string, version int, id, method string, inArgs, outResults interface{}) error {
   145  			if len(args) > *numCalls {
   146  				checkArgs(c, &args[*numCalls], facade, version, id, method, inArgs, outResults)
   147  			}
   148  			*numCalls++
   149  			return err
   150  		},
   151  	)
   152  }
   153  
   154  // StubFacadeCaller is a testing stub implementation of api/base.FacadeCaller.
   155  type StubFacadeCaller struct {
   156  	// Stub is the raw stub used to track calls and errors.
   157  	Stub *testing.Stub
   158  	// These control the values returned by the stub's methods.
   159  	FacadeCallFn         func(name string, params, response interface{}) error
   160  	ReturnName           string
   161  	ReturnBestAPIVersion int
   162  	ReturnRawAPICaller   base.APICaller
   163  }
   164  
   165  // FacadeCall implements api/base.FacadeCaller.
   166  func (s *StubFacadeCaller) FacadeCall(request string, params, response interface{}) error {
   167  	s.Stub.AddCall("FacadeCall", request, params, response)
   168  	if err := s.Stub.NextErr(); err != nil {
   169  		return errors.Trace(err)
   170  	}
   171  
   172  	if s.FacadeCallFn != nil {
   173  		return s.FacadeCallFn(request, params, response)
   174  	}
   175  	return nil
   176  }
   177  
   178  // Name implements api/base.FacadeCaller.
   179  func (s *StubFacadeCaller) Name() string {
   180  	s.Stub.AddCall("Name")
   181  	s.Stub.PopNoErr()
   182  
   183  	return s.ReturnName
   184  }
   185  
   186  // BestAPIVersion implements api/base.FacadeCaller.
   187  func (s *StubFacadeCaller) BestAPIVersion() int {
   188  	s.Stub.AddCall("BestAPIVersion")
   189  	s.Stub.PopNoErr()
   190  
   191  	return s.ReturnBestAPIVersion
   192  }
   193  
   194  // RawAPICaller implements api/base.FacadeCaller.
   195  func (s *StubFacadeCaller) RawAPICaller() base.APICaller {
   196  	s.Stub.AddCall("RawAPICaller")
   197  	s.Stub.PopNoErr()
   198  
   199  	return s.ReturnRawAPICaller
   200  }