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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 := ¶ms.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 ¶ms.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 := ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 ¶ms.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 }