github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/controller/charmrevisionupdater/interface_test.go (about)

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package charmrevisionupdater_test
     5  
     6  import (
     7  	"github.com/juju/charm/v12"
     8  	"github.com/juju/charm/v12/resource"
     9  	"github.com/juju/names/v5"
    10  	jc "github.com/juju/testing/checkers"
    11  	"go.uber.org/mock/gomock"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/apiserver/facade"
    15  	"github.com/juju/juju/apiserver/facades/controller/charmrevisionupdater"
    16  	"github.com/juju/juju/apiserver/facades/controller/charmrevisionupdater/mocks"
    17  	"github.com/juju/juju/charmhub"
    18  	charmmetrics "github.com/juju/juju/core/charm/metrics"
    19  	"github.com/juju/juju/state"
    20  )
    21  
    22  func makeApplication(ctrl *gomock.Controller, schema, charmName, charmID, appID string, revision int) charmrevisionupdater.Application {
    23  	app := mocks.NewMockApplication(ctrl)
    24  
    25  	var source string
    26  	switch schema {
    27  	case "ch":
    28  		source = "charm-hub"
    29  		app.EXPECT().UnitCount().Return(2).AnyTimes()
    30  	}
    31  
    32  	curl := &charm.URL{
    33  		Schema:   schema,
    34  		Name:     charmName,
    35  		Revision: revision,
    36  	}
    37  	str := curl.String()
    38  	app.EXPECT().CharmURL().Return(&str, false).AnyTimes()
    39  	app.EXPECT().CharmOrigin().Return(&state.CharmOrigin{
    40  		Source:   source,
    41  		Type:     "charm",
    42  		ID:       charmID,
    43  		Revision: &revision,
    44  		Channel: &state.Channel{
    45  			Track: "latest",
    46  			Risk:  "stable",
    47  		},
    48  		Platform: &state.Platform{
    49  			Architecture: "amd64",
    50  			OS:           "ubuntu",
    51  			Channel:      "20.04/stable",
    52  		},
    53  	}).AnyTimes()
    54  	app.EXPECT().ApplicationTag().Return(names.ApplicationTag{Name: appID}).AnyTimes()
    55  
    56  	return app
    57  }
    58  
    59  func makeResource(c *gc.C, name string, revision, size int, hexFingerprint string) resource.Resource {
    60  	fingerprint, err := resource.ParseFingerprint(hexFingerprint)
    61  	c.Assert(err, jc.ErrorIsNil)
    62  	return resource.Resource{
    63  		Meta: resource.Meta{
    64  			Name: name,
    65  			Type: resource.TypeFile,
    66  		},
    67  		Origin:      resource.OriginStore,
    68  		Revision:    revision,
    69  		Fingerprint: fingerprint,
    70  		Size:        int64(size),
    71  	}
    72  }
    73  
    74  // charmhubConfigMatcher matches only the charm IDs and revisions of a
    75  // charmhub.RefreshMany config.
    76  type charmhubConfigMatcher struct {
    77  	expected []charmhubConfigExpected
    78  }
    79  
    80  type charmhubConfigExpected struct {
    81  	id        string
    82  	revision  int
    83  	relMetric string
    84  }
    85  
    86  func (m charmhubConfigMatcher) Matches(x interface{}) bool {
    87  	config, ok := x.(charmhub.RefreshConfig)
    88  	if !ok {
    89  		return false
    90  	}
    91  	request, err := config.Build()
    92  	if err != nil {
    93  		return false
    94  	}
    95  	if len(request.Context) != len(m.expected) || len(request.Actions) != len(m.expected) {
    96  		return false
    97  	}
    98  	for i, context := range request.Context {
    99  		if context.ID != m.expected[i].id {
   100  			return false
   101  		}
   102  		if context.Revision != m.expected[i].revision {
   103  			return false
   104  		}
   105  		r, ok := context.Metrics[string(charmmetrics.Relations)]
   106  		if m.expected[i].relMetric != "" && !ok {
   107  			return false
   108  		}
   109  		if m.expected[i].relMetric != "" && ok && r != m.expected[i].relMetric {
   110  			return false
   111  		}
   112  		action := request.Actions[i]
   113  		if *action.ID != m.expected[i].id {
   114  			return false
   115  		}
   116  		_, ok = context.Metrics[string(charmmetrics.NumUnits)]
   117  		if m.expected[i].relMetric != "" && !ok {
   118  			return false
   119  		}
   120  	}
   121  	return true
   122  }
   123  
   124  func (charmhubConfigMatcher) String() string {
   125  	return "matches config"
   126  }
   127  
   128  // charmhubMetricsMatcher matches the controller and model parts of the metrics, then
   129  // a value within each part.
   130  type charmhubMetricsMatcher struct {
   131  	c     *gc.C
   132  	exist bool
   133  }
   134  
   135  func (m charmhubMetricsMatcher) Matches(x interface{}) bool {
   136  	switch y := x.(type) {
   137  	case map[charmmetrics.MetricKey]map[charmmetrics.MetricKey]string:
   138  		if len(y) != 2 {
   139  			if !m.exist {
   140  				return true
   141  			}
   142  			return false
   143  		}
   144  		for k := range y {
   145  			if k != charmmetrics.Controller && k != charmmetrics.Model {
   146  				return false
   147  			}
   148  		}
   149  		controller := y[charmmetrics.Controller]
   150  		uuid, ok := controller[charmmetrics.UUID]
   151  		if !ok {
   152  			return false
   153  		}
   154  		m.c.Assert(uuid, gc.Equals, "controller-1")
   155  
   156  		model := y[charmmetrics.Model]
   157  		cloud, ok := model[charmmetrics.Cloud]
   158  		if !ok {
   159  			return false
   160  		}
   161  		m.c.Assert(cloud, gc.Equals, "cloud")
   162  	default:
   163  		return false
   164  	}
   165  	return true
   166  }
   167  
   168  func (charmhubMetricsMatcher) String() string {
   169  	return "matches metrics"
   170  }
   171  
   172  type facadeContextShim struct {
   173  	facade.Context // Make it fulfil the interface, but we only define a couple of methods
   174  	state          *state.State
   175  	authorizer     facade.Authorizer
   176  }
   177  
   178  func (s facadeContextShim) Auth() facade.Authorizer {
   179  	return s.authorizer
   180  }
   181  
   182  func (s facadeContextShim) State() *state.State {
   183  	return s.state
   184  }