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: &params.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  }