github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/client/resources/server_addpending_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package resources_test 5 6 import ( 7 "github.com/juju/charm/v12" 8 charmresource "github.com/juju/charm/v12/resource" 9 "github.com/juju/errors" 10 "github.com/juju/names/v5" 11 jc "github.com/juju/testing/checkers" 12 "go.uber.org/mock/gomock" 13 gc "gopkg.in/check.v1" 14 15 corecharm "github.com/juju/juju/core/charm" 16 "github.com/juju/juju/rpc/params" 17 ) 18 19 var _ = gc.Suite(&AddPendingResourcesSuite{}) 20 21 type AddPendingResourcesSuite struct { 22 BaseSuite 23 } 24 25 func (s *AddPendingResourcesSuite) TestNoURL(c *gc.C) { 26 defer s.setUpTest(c).Finish() 27 _, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 28 id1 := "some-unique-ID" 29 aTag := names.NewApplicationTag("a-application") 30 s.backend.EXPECT().AddPendingResource(aTag.Id(), "", resourceMatcher{c: c}).Return(id1, nil) 31 facade := s.newFacade(c) 32 33 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 34 Entity: params.Entity{ 35 Tag: aTag.String(), 36 }, 37 Resources: []params.CharmResource{ 38 apiRes1.CharmResource, 39 }, 40 }) 41 c.Assert(err, jc.ErrorIsNil) 42 43 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 44 PendingIDs: []string{ 45 id1, 46 }, 47 }) 48 } 49 50 func (s *AddPendingResourcesSuite) TestWithURLUpToDate(c *gc.C) { 51 defer s.setUpTest(c).Finish() 52 res1, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 53 res1.Origin = charmresource.OriginStore 54 res1.Revision = 3 55 apiRes1.Origin = charmresource.OriginStore.String() 56 apiRes1.Revision = 3 57 id1 := "some-unique-ID" 58 aTag := names.NewApplicationTag("a-application") 59 s.backend.EXPECT().AddPendingResource(aTag.Id(), gomock.Any(), resourceMatcher{c: c}).Return(id1, nil) 60 res := []charmresource.Resource{ 61 res1.Resource, 62 } 63 s.factory.EXPECT().ResolveResources(gomock.Any(), gomock.Any()).Return(res, nil) 64 facade := s.newFacade(c) 65 66 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 67 Entity: params.Entity{ 68 Tag: aTag.String(), 69 }, 70 URL: "ch:amd64/jammy/spam-5", 71 Resources: []params.CharmResource{ 72 apiRes1.CharmResource, 73 }, 74 }) 75 c.Assert(err, jc.ErrorIsNil) 76 c.Assert(result.Error, gc.IsNil) 77 78 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 79 PendingIDs: []string{ 80 id1, 81 }, 82 }) 83 } 84 85 func (s *AddPendingResourcesSuite) TestWithURLMismatchComplete(c *gc.C) { 86 defer s.setUpTest(c).Finish() 87 res1, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 88 res1.Origin = charmresource.OriginStore 89 res1.Revision = 3 90 apiRes1.Origin = charmresource.OriginStore.String() 91 apiRes1.Revision = 3 92 id1 := "some-unique-ID" 93 aTag := names.NewApplicationTag("a-application") 94 s.backend.EXPECT().AddPendingResource(aTag.Id(), gomock.Any(), resourceMatcher{c: c}).Return(id1, nil) 95 curl := charm.MustParseURL("ch:amd64/jammy/spam-5") 96 charmID := corecharm.CharmID{ 97 URL: curl, 98 Origin: corecharm.Origin{Channel: &charm.Channel{}}, 99 } 100 expected := []charmresource.Resource{res1.Resource} 101 s.factory.EXPECT().ResolveResources(expected, charmID).Return(expected, nil) 102 103 facade := s.newFacade(c) 104 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 105 Entity: params.Entity{ 106 Tag: aTag.String(), 107 }, 108 URL: curl.String(), 109 Resources: []params.CharmResource{ 110 apiRes1.CharmResource, 111 }, 112 }) 113 c.Assert(err, jc.ErrorIsNil) 114 c.Assert(result.Error, gc.IsNil) 115 116 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 117 PendingIDs: []string{ 118 id1, 119 }, 120 }) 121 } 122 123 func (s *AddPendingResourcesSuite) TestWithURLMismatchIncomplete(c *gc.C) { 124 defer s.setUpTest(c).Finish() 125 res1, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 126 res1.Origin = charmresource.OriginStore 127 res1.Revision = 2 128 apiRes1.Origin = charmresource.OriginStore.String() 129 apiRes1.Revision = 3 130 apiRes1.Fingerprint = nil 131 apiRes1.Size = 0 132 id1 := "some-unique-ID" 133 aTag := names.NewApplicationTag("a-application") 134 s.backend.EXPECT().AddPendingResource(aTag.Id(), gomock.Any(), resourceMatcher{c: c}).Return(id1, nil) 135 expected := []charmresource.Resource{{ 136 Meta: res1.Meta, 137 Origin: charmresource.OriginStore, 138 Revision: 3, 139 Fingerprint: res1.Fingerprint, 140 Size: res1.Size, 141 }} 142 res2 := []charmresource.Resource{{ 143 Meta: res1.Meta, 144 Origin: charmresource.OriginStore, 145 Revision: 3, 146 }} 147 curl := charm.MustParseURL("ch:amd64/jammy/spam-5") 148 charmID := corecharm.CharmID{ 149 URL: curl, 150 Origin: corecharm.Origin{Channel: &charm.Channel{}}, 151 } 152 s.factory.EXPECT().ResolveResources(res2, charmID).Return(expected, nil) 153 154 facade := s.newFacade(c) 155 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 156 Entity: params.Entity{ 157 Tag: aTag.String(), 158 }, 159 URL: curl.String(), 160 Resources: []params.CharmResource{ 161 apiRes1.CharmResource, 162 }, 163 }) 164 c.Assert(err, jc.ErrorIsNil) 165 166 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 167 PendingIDs: []string{ 168 id1, 169 }, 170 }) 171 } 172 173 func (s *AddPendingResourcesSuite) TestWithURLNoRevision(c *gc.C) { 174 defer s.setUpTest(c).Finish() 175 res1, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 176 res1.Origin = charmresource.OriginStore 177 res1.Revision = 3 178 res1.Size = 10 179 apiRes1.Origin = charmresource.OriginStore.String() 180 apiRes1.Revision = -1 181 apiRes1.Size = 0 182 apiRes1.Fingerprint = nil 183 resNoRev := []charmresource.Resource{{ 184 Meta: res1.Meta, 185 Origin: charmresource.OriginStore, 186 Revision: -1, 187 }} 188 id1 := "some-unique-ID" 189 aTag := names.NewApplicationTag("a-application") 190 s.backend.EXPECT().AddPendingResource(aTag.Id(), gomock.Any(), resourceMatcher{c: c}).Return(id1, nil) 191 csRes := res1 // a copy 192 csRes.Revision = 3 193 csRes.Size = 10 194 expected := []charmresource.Resource{csRes.Resource} 195 curl := charm.MustParseURL("ch:amd64/jammy/spam-5") 196 charmID := corecharm.CharmID{ 197 URL: curl, 198 Origin: corecharm.Origin{Channel: &charm.Channel{}}, 199 } 200 s.factory.EXPECT().ResolveResources(resNoRev, charmID).Return(expected, nil) 201 202 facade := s.newFacade(c) 203 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 204 Entity: params.Entity{ 205 Tag: aTag.String(), 206 }, 207 URL: curl.String(), 208 Resources: []params.CharmResource{ 209 apiRes1.CharmResource, 210 }, 211 }) 212 c.Assert(err, jc.ErrorIsNil) 213 c.Assert(result.Error, gc.IsNil) 214 215 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 216 PendingIDs: []string{ 217 id1, 218 }, 219 }) 220 } 221 222 func (s *AddPendingResourcesSuite) TestWithURLUpload(c *gc.C) { 223 defer s.setUpTest(c).Finish() 224 res1, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 225 res1.Origin = charmresource.OriginUpload 226 res1.Revision = 0 227 apiRes1.Origin = charmresource.OriginUpload.String() 228 apiRes1.Revision = 0 229 id1 := "some-unique-ID" 230 aTag := names.NewApplicationTag("a-application") 231 s.backend.EXPECT().AddPendingResource(aTag.Id(), gomock.Any(), resourceMatcher{c: c}).Return(id1, nil) 232 csRes := res1 // a copy 233 csRes.Origin = charmresource.OriginStore 234 csRes.Revision = 3 235 expected := []charmresource.Resource{csRes.Resource} 236 curl := charm.MustParseURL("ch:amd64/jammy/spam-5") 237 charmID := corecharm.CharmID{ 238 URL: curl, 239 Origin: corecharm.Origin{Channel: &charm.Channel{}}, 240 } 241 s.factory.EXPECT().ResolveResources([]charmresource.Resource{res1.Resource}, charmID).Return(expected, nil) 242 243 facade := s.newFacade(c) 244 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 245 Entity: params.Entity{ 246 Tag: aTag.String(), 247 }, 248 URL: curl.String(), 249 Resources: []params.CharmResource{ 250 apiRes1.CharmResource, 251 }, 252 }) 253 c.Assert(err, jc.ErrorIsNil) 254 c.Assert(result.Error, gc.IsNil) 255 256 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 257 PendingIDs: []string{ 258 id1, 259 }, 260 }) 261 } 262 263 func (s *AddPendingResourcesSuite) TestUnknownResource(c *gc.C) { 264 defer s.setUpTest(c).Finish() 265 res1, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 266 res1.Origin = charmresource.OriginStore 267 res1.Revision = 3 268 apiRes1.Origin = charmresource.OriginStore.String() 269 apiRes1.Revision = 3 270 id1 := "some-unique-ID" 271 aTag := names.NewApplicationTag("a-application") 272 s.backend.EXPECT().AddPendingResource(aTag.Id(), gomock.Any(), resourceMatcher{c: c}).Return(id1, nil) 273 expected := []charmresource.Resource{res1.Resource} 274 curl := charm.MustParseURL("ch:amd64/jammy/spam-5") 275 charmID := corecharm.CharmID{ 276 URL: curl, 277 Origin: corecharm.Origin{Channel: &charm.Channel{}}, 278 } 279 s.factory.EXPECT().ResolveResources(expected, charmID).Return(expected, nil) 280 281 facade := s.newFacade(c) 282 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 283 Entity: params.Entity{ 284 Tag: aTag.String(), 285 }, 286 URL: curl.String(), 287 Resources: []params.CharmResource{ 288 apiRes1.CharmResource, 289 }, 290 }) 291 c.Assert(err, jc.ErrorIsNil) 292 293 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 294 PendingIDs: []string{ 295 id1, 296 }, 297 }) 298 } 299 300 func (s *AddPendingResourcesSuite) TestDataStoreError(c *gc.C) { 301 defer s.setUpTest(c).Finish() 302 _, apiRes1 := newResource(c, "spam", "a-user", "spamspamspam") 303 failure := errors.New("<failure>") 304 s.backend.EXPECT().AddPendingResource(gomock.Any(), gomock.Any(), gomock.Any()).Return("", failure) 305 306 facade := s.newFacade(c) 307 result, err := facade.AddPendingResources(params.AddPendingResourcesArgsV2{ 308 Entity: params.Entity{ 309 Tag: "application-a-application", 310 }, 311 Resources: []params.CharmResource{ 312 apiRes1.CharmResource, 313 }, 314 }) 315 c.Assert(err, jc.ErrorIsNil) 316 317 c.Check(result, jc.DeepEquals, params.AddPendingResourcesResult{ 318 ErrorResult: params.ErrorResult{Error: ¶ms.Error{ 319 Message: `while adding pending resource info for "spam": <failure>`, 320 }}, 321 }) 322 } 323 324 type resourceMatcher struct { 325 c *gc.C 326 } 327 328 func (m resourceMatcher) Matches(x interface{}) bool { 329 in, ok := x.(charmresource.Resource) 330 if !ok { 331 m.c.Fatal("wrong type") 332 return false 333 } 334 if err := in.Validate(); err != nil { 335 m.c.Logf("from Validate: %s", err) 336 return false 337 } 338 return true 339 } 340 341 func (m resourceMatcher) String() string { 342 return "match resource" 343 }