github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/api/agent/uniter/payload_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package uniter_test
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  	"github.com/juju/names/v5"
     9  	"github.com/juju/testing"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/api/agent/uniter"
    14  	"github.com/juju/juju/api/base"
    15  	api "github.com/juju/juju/api/client/payloads"
    16  	apiservererrors "github.com/juju/juju/apiserver/errors"
    17  	"github.com/juju/juju/core/payloads"
    18  	"github.com/juju/juju/rpc/params"
    19  )
    20  
    21  type clientSuite struct {
    22  	testing.IsolationSuite
    23  
    24  	stub    *testing.Stub
    25  	facade  *stubFacade
    26  	payload params.Payload
    27  }
    28  
    29  var _ = gc.Suite(&clientSuite{})
    30  
    31  func (s *clientSuite) SetUpTest(c *gc.C) {
    32  	s.IsolationSuite.SetUpTest(c)
    33  
    34  	s.stub = &testing.Stub{}
    35  	s.facade = &stubFacade{stub: s.stub}
    36  	s.facade.methods = &unitMethods{}
    37  	s.payload = params.Payload{
    38  		Class:  "foobar",
    39  		Type:   "type",
    40  		ID:     "idfoo",
    41  		Status: payloads.StateRunning,
    42  	}
    43  
    44  }
    45  
    46  func (s *clientSuite) TestTrack(c *gc.C) {
    47  	id := "ce5bc2a7-65d8-4800-8199-a7c3356ab309"
    48  	numStubCalls := 0
    49  	s.facade.FacadeCallFn = func(name string, args, response interface{}) error {
    50  		numStubCalls++
    51  		c.Check(name, gc.Equals, "Track")
    52  
    53  		typedResponse, ok := response.(*params.PayloadResults)
    54  		c.Assert(ok, gc.Equals, true)
    55  		typedResponse.Results = []params.PayloadResult{{
    56  			Entity: params.Entity{
    57  				Tag: names.NewPayloadTag(id).String(),
    58  			},
    59  			Payload:  nil,
    60  			NotFound: false,
    61  			Error:    nil,
    62  		}}
    63  		return nil
    64  	}
    65  
    66  	pclient := uniter.NewPayloadFacadeClient(s.facade)
    67  
    68  	pl, err := api.API2Payload(s.payload)
    69  	c.Assert(err, jc.ErrorIsNil)
    70  	results, err := pclient.Track(pl.Payload)
    71  	c.Assert(err, jc.ErrorIsNil)
    72  
    73  	c.Check(numStubCalls, gc.Equals, 1)
    74  	c.Check(results, jc.DeepEquals, []payloads.Result{{
    75  		ID:       id,
    76  		Payload:  nil,
    77  		NotFound: false,
    78  		Error:    nil,
    79  	}})
    80  }
    81  
    82  func (s *clientSuite) TestList(c *gc.C) {
    83  	id := "ce5bc2a7-65d8-4800-8199-a7c3356ab309"
    84  	responses := []interface{}{
    85  		&params.PayloadResults{
    86  			Results: []params.PayloadResult{{
    87  				Entity: params.Entity{
    88  					Tag: names.NewPayloadTag(id).String(),
    89  				},
    90  				Payload:  nil,
    91  				NotFound: false,
    92  				Error:    nil,
    93  			}},
    94  		},
    95  		&params.PayloadResults{
    96  			Results: []params.PayloadResult{{
    97  				Entity: params.Entity{
    98  					Tag: names.NewPayloadTag(id).String(),
    99  				},
   100  				Payload:  &s.payload,
   101  				NotFound: false,
   102  				Error:    nil,
   103  			}},
   104  		},
   105  	}
   106  	s.facade.responses = append(s.facade.responses, responses...)
   107  
   108  	pclient := uniter.NewPayloadFacadeClient(s.facade)
   109  
   110  	results, err := pclient.List("idfoo/bar")
   111  	c.Assert(err, jc.ErrorIsNil)
   112  
   113  	expected, err := api.API2Payload(s.payload)
   114  	c.Assert(err, jc.ErrorIsNil)
   115  	c.Check(results, jc.DeepEquals, []payloads.Result{{
   116  		ID:       id,
   117  		Payload:  &expected,
   118  		NotFound: false,
   119  		Error:    nil,
   120  	}})
   121  	s.stub.CheckCalls(c, []testing.StubCall{{
   122  		FuncName: "LookUp",
   123  		Args: []interface{}{
   124  			&params.LookUpPayloadArgs{
   125  				Args: []params.LookUpPayloadArg{{
   126  					Name: "idfoo",
   127  					ID:   "bar",
   128  				}},
   129  			},
   130  			responses[0],
   131  		},
   132  	}, {
   133  		FuncName: "List",
   134  		Args: []interface{}{
   135  			&params.Entities{
   136  				Entities: []params.Entity{{
   137  					Tag: names.NewPayloadTag(id).String(),
   138  				}},
   139  			},
   140  			responses[1],
   141  		},
   142  	}})
   143  }
   144  
   145  func (s *clientSuite) TestLookUpOkay(c *gc.C) {
   146  	id := "ce5bc2a7-65d8-4800-8199-a7c3356ab309"
   147  	response := &params.PayloadResults{
   148  		Results: []params.PayloadResult{{
   149  			Entity: params.Entity{
   150  				Tag: names.NewPayloadTag(id).String(),
   151  			},
   152  			Payload:  nil,
   153  			NotFound: false,
   154  			Error:    nil,
   155  		}},
   156  	}
   157  	s.facade.responses = append(s.facade.responses, response)
   158  
   159  	pclient := uniter.NewPayloadFacadeClient(s.facade)
   160  	results, err := pclient.LookUp("idfoo/bar")
   161  	c.Assert(err, jc.ErrorIsNil)
   162  
   163  	c.Check(results, jc.DeepEquals, []payloads.Result{{
   164  		ID:       id,
   165  		Payload:  nil,
   166  		NotFound: false,
   167  		Error:    nil,
   168  	}})
   169  	s.stub.CheckCalls(c, []testing.StubCall{{
   170  		FuncName: "LookUp",
   171  		Args: []interface{}{
   172  			&params.LookUpPayloadArgs{
   173  				Args: []params.LookUpPayloadArg{{
   174  					Name: "idfoo",
   175  					ID:   "bar",
   176  				}},
   177  			},
   178  			response,
   179  		},
   180  	}})
   181  }
   182  
   183  func (s *clientSuite) TestLookUpMulti(c *gc.C) {
   184  	id1 := "ce5bc2a7-65d8-4800-8199-a7c3356ab309"
   185  	id2 := "ce5bc2a7-65d8-4800-8199-a7c3356ab311"
   186  	response := &params.PayloadResults{
   187  		Results: []params.PayloadResult{{
   188  			Entity: params.Entity{
   189  				Tag: names.NewPayloadTag(id1).String(),
   190  			},
   191  			Payload:  nil,
   192  			NotFound: false,
   193  			Error:    nil,
   194  		}, {
   195  			Entity: params.Entity{
   196  				Tag: "",
   197  			},
   198  			Payload:  nil,
   199  			NotFound: true,
   200  			Error:    apiservererrors.ServerError(errors.NotFoundf("payload")),
   201  		}, {
   202  			Entity: params.Entity{
   203  				Tag: names.NewPayloadTag(id2).String(),
   204  			},
   205  			Payload:  nil,
   206  			NotFound: false,
   207  			Error:    nil,
   208  		}},
   209  	}
   210  	s.facade.responses = append(s.facade.responses, response)
   211  
   212  	pclient := uniter.NewPayloadFacadeClient(s.facade)
   213  	results, err := pclient.LookUp("idfoo/bar", "idbaz/bam", "spam/eggs")
   214  	c.Assert(err, jc.ErrorIsNil)
   215  
   216  	c.Assert(results, gc.HasLen, 3)
   217  	c.Assert(results[1].Error, gc.NotNil)
   218  	results[1].Error = nil
   219  	c.Check(results, jc.DeepEquals, []payloads.Result{{
   220  		ID:       id1,
   221  		Payload:  nil,
   222  		NotFound: false,
   223  		Error:    nil,
   224  	}, {
   225  		ID:       "",
   226  		Payload:  nil,
   227  		NotFound: true,
   228  		Error:    nil,
   229  	}, {
   230  		ID:       id2,
   231  		Payload:  nil,
   232  		NotFound: false,
   233  		Error:    nil,
   234  	}})
   235  	s.stub.CheckCalls(c, []testing.StubCall{{
   236  		FuncName: "LookUp",
   237  		Args: []interface{}{
   238  			&params.LookUpPayloadArgs{
   239  				Args: []params.LookUpPayloadArg{{
   240  					Name: "idfoo",
   241  					ID:   "bar",
   242  				}, {
   243  					Name: "idbaz",
   244  					ID:   "bam",
   245  				}, {
   246  					Name: "spam",
   247  					ID:   "eggs",
   248  				}},
   249  			},
   250  			response,
   251  		},
   252  	}})
   253  }
   254  
   255  func (s *clientSuite) TestSetStatus(c *gc.C) {
   256  	id := "ce5bc2a7-65d8-4800-8199-a7c3356ab309"
   257  	responses := []interface{}{
   258  		&params.PayloadResults{
   259  			Results: []params.PayloadResult{{
   260  				Entity: params.Entity{
   261  					Tag: names.NewPayloadTag(id).String(),
   262  				},
   263  				Payload:  nil,
   264  				NotFound: false,
   265  				Error:    nil,
   266  			}},
   267  		},
   268  		&params.PayloadResults{
   269  			Results: []params.PayloadResult{{
   270  				Entity: params.Entity{
   271  					Tag: names.NewPayloadTag(id).String(),
   272  				},
   273  				Payload:  nil,
   274  				NotFound: false,
   275  				Error:    nil,
   276  			}},
   277  		},
   278  	}
   279  	s.facade.responses = append(s.facade.responses, responses...)
   280  
   281  	pclient := uniter.NewPayloadFacadeClient(s.facade)
   282  	results, err := pclient.SetStatus(payloads.StateRunning, "idfoo/bar")
   283  	c.Assert(err, jc.ErrorIsNil)
   284  
   285  	c.Check(results, jc.DeepEquals, []payloads.Result{{
   286  		ID:       id,
   287  		Payload:  nil,
   288  		NotFound: false,
   289  		Error:    nil,
   290  	}})
   291  	s.stub.CheckCalls(c, []testing.StubCall{{
   292  		FuncName: "LookUp",
   293  		Args: []interface{}{
   294  			&params.LookUpPayloadArgs{
   295  				Args: []params.LookUpPayloadArg{{
   296  					Name: "idfoo",
   297  					ID:   "bar",
   298  				}},
   299  			},
   300  			responses[0],
   301  		},
   302  	}, {
   303  		FuncName: "SetStatus",
   304  		Args: []interface{}{
   305  			&params.SetPayloadStatusArgs{
   306  				Args: []params.SetPayloadStatusArg{{
   307  					Entity: params.Entity{
   308  						Tag: names.NewPayloadTag(id).String(),
   309  					},
   310  					Status: "running",
   311  				}},
   312  			},
   313  			responses[1],
   314  		},
   315  	}})
   316  }
   317  
   318  func (s *clientSuite) TestUntrack(c *gc.C) {
   319  	id := "ce5bc2a7-65d8-4800-8199-a7c3356ab309"
   320  	responses := []interface{}{
   321  		&params.PayloadResults{
   322  			Results: []params.PayloadResult{{
   323  				Entity: params.Entity{
   324  					Tag: names.NewPayloadTag(id).String(),
   325  				},
   326  				Payload:  nil,
   327  				NotFound: false,
   328  				Error:    nil,
   329  			}},
   330  		},
   331  		&params.PayloadResults{
   332  			Results: []params.PayloadResult{{
   333  				Entity: params.Entity{
   334  					Tag: names.NewPayloadTag(id).String(),
   335  				},
   336  				Payload:  nil,
   337  				NotFound: false,
   338  				Error:    nil,
   339  			}},
   340  		},
   341  	}
   342  	s.facade.responses = append(s.facade.responses, responses...)
   343  
   344  	pclient := uniter.NewPayloadFacadeClient(s.facade)
   345  	results, err := pclient.Untrack("idfoo/bar")
   346  	c.Assert(err, jc.ErrorIsNil)
   347  
   348  	c.Check(results, jc.DeepEquals, []payloads.Result{{
   349  		ID:       id,
   350  		Payload:  nil,
   351  		NotFound: false,
   352  		Error:    nil,
   353  	}})
   354  	s.stub.CheckCalls(c, []testing.StubCall{{
   355  		FuncName: "LookUp",
   356  		Args: []interface{}{
   357  			&params.LookUpPayloadArgs{
   358  				Args: []params.LookUpPayloadArg{{
   359  					Name: "idfoo",
   360  					ID:   "bar",
   361  				}},
   362  			},
   363  			responses[0],
   364  		},
   365  	}, {
   366  		FuncName: "Untrack",
   367  		Args: []interface{}{
   368  			&params.Entities{
   369  				Entities: []params.Entity{{
   370  					Tag: names.NewPayloadTag(id).String(),
   371  				}},
   372  			},
   373  			responses[1],
   374  		},
   375  	}})
   376  }
   377  
   378  type apiMethods interface {
   379  	Handler(name string) (func(target, response interface{}), bool)
   380  }
   381  
   382  type stubFacade struct {
   383  	base.APICaller
   384  	stub      *testing.Stub
   385  	responses []interface{}
   386  	methods   apiMethods
   387  
   388  	// TODO(ericsnow) Eliminate this.
   389  	FacadeCallFn func(name string, params, response interface{}) error
   390  }
   391  
   392  func (s *stubFacade) nextResponse() interface{} {
   393  	if len(s.responses) == 0 {
   394  		return nil
   395  	}
   396  	resp := s.responses[0]
   397  	s.responses = s.responses[1:]
   398  	return resp
   399  }
   400  
   401  func (s *stubFacade) BestFacadeVersion(_ string) int {
   402  	return 1
   403  }
   404  
   405  func (s *stubFacade) APICall(objType string, version int, id, request string, args, response interface{}) error {
   406  	s.stub.AddCall(request, args, response)
   407  	resp := s.nextResponse()
   408  	if err := s.stub.NextErr(); err != nil {
   409  		return errors.Trace(err)
   410  	}
   411  
   412  	if s.FacadeCallFn != nil {
   413  		return s.FacadeCallFn(request, args, response)
   414  	}
   415  
   416  	if resp == nil {
   417  		// TODO(ericsnow) Fail?
   418  		return nil
   419  	}
   420  	handler, ok := s.methods.Handler(request)
   421  	if !ok {
   422  		return errors.Errorf("unknown request %q", request)
   423  	}
   424  	handler(response, resp)
   425  	return nil
   426  }
   427  
   428  type unitMethods struct{}
   429  
   430  func (m unitMethods) Handler(name string) (func(target, response interface{}), bool) {
   431  	switch name {
   432  	case "List", "LookUp", "SetStatus", "Untrack":
   433  		return m.generic, true
   434  	default:
   435  		return nil, false
   436  	}
   437  }
   438  
   439  func (unitMethods) generic(target, response interface{}) {
   440  	typedTarget := target.(*params.PayloadResults)
   441  	typedResponse := response.(*params.PayloadResults)
   442  	*typedTarget = *typedResponse
   443  }