github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/shared_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/loggo"
    12  	"github.com/juju/pubsub/v2"
    13  	jc "github.com/juju/testing/checkers"
    14  	"github.com/juju/worker/v3/workertest"
    15  	"github.com/prometheus/client_golang/prometheus"
    16  	gc "gopkg.in/check.v1"
    17  
    18  	corecontroller "github.com/juju/juju/controller"
    19  	"github.com/juju/juju/core/cache"
    20  	"github.com/juju/juju/core/presence"
    21  	"github.com/juju/juju/pubsub/controller"
    22  	"github.com/juju/juju/state"
    23  	statetesting "github.com/juju/juju/state/testing"
    24  	"github.com/juju/juju/testing"
    25  	"github.com/juju/juju/worker/gate"
    26  	"github.com/juju/juju/worker/lease"
    27  	"github.com/juju/juju/worker/modelcache"
    28  	"github.com/juju/juju/worker/multiwatcher"
    29  )
    30  
    31  type sharedServerContextSuite struct {
    32  	statetesting.StateSuite
    33  
    34  	hub    *pubsub.StructuredHub
    35  	config sharedServerConfig
    36  }
    37  
    38  var _ = gc.Suite(&sharedServerContextSuite{})
    39  
    40  func (s *sharedServerContextSuite) SetUpTest(c *gc.C) {
    41  	s.StateSuite.SetUpTest(c)
    42  
    43  	allWatcherBacking, err := state.NewAllWatcherBacking(s.StatePool)
    44  	c.Assert(err, jc.ErrorIsNil)
    45  	multiWatcherWorker, err := multiwatcher.NewWorker(multiwatcher.Config{
    46  		Clock:                clock.WallClock,
    47  		Logger:               loggo.GetLogger("test"),
    48  		Backing:              allWatcherBacking,
    49  		PrometheusRegisterer: noopRegisterer{},
    50  	})
    51  	c.Assert(err, jc.ErrorIsNil)
    52  	// The worker itself is a coremultiwatcher.Factory.
    53  	s.AddCleanup(func(c *gc.C) { workertest.CleanKill(c, multiWatcherWorker) })
    54  
    55  	initialized := gate.NewLock()
    56  	s.hub = pubsub.NewStructuredHub(nil)
    57  	modelCache, err := modelcache.NewWorker(modelcache.Config{
    58  		StatePool:            s.StatePool,
    59  		Hub:                  s.hub,
    60  		InitializedGate:      initialized,
    61  		Logger:               loggo.GetLogger("test"),
    62  		WatcherFactory:       multiWatcherWorker.WatchController,
    63  		PrometheusRegisterer: noopRegisterer{},
    64  		Cleanup:              func() {},
    65  	}.WithDefaultRestartStrategy())
    66  	s.AddCleanup(func(c *gc.C) { workertest.CleanKill(c, modelCache) })
    67  	c.Assert(err, jc.ErrorIsNil)
    68  	var controller *cache.Controller
    69  	err = modelcache.ExtractCacheController(modelCache, &controller)
    70  	c.Assert(err, jc.ErrorIsNil)
    71  
    72  	controllerConfig, err := s.State.ControllerConfig()
    73  	c.Assert(err, jc.ErrorIsNil)
    74  
    75  	s.config = sharedServerConfig{
    76  		statePool:           s.StatePool,
    77  		controller:          controller,
    78  		multiwatcherFactory: multiWatcherWorker,
    79  		centralHub:          s.hub,
    80  		presence:            presence.New(clock.WallClock),
    81  		leaseManager:        &lease.Manager{},
    82  		controllerConfig:    controllerConfig,
    83  		logger:              loggo.GetLogger("test"),
    84  		dbGetter:            StubDBGetter{},
    85  	}
    86  }
    87  
    88  func (s *sharedServerContextSuite) TestConfigNoStatePool(c *gc.C) {
    89  	s.config.statePool = nil
    90  	err := s.config.validate()
    91  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    92  	c.Check(err, gc.ErrorMatches, "nil statePool not valid")
    93  }
    94  
    95  func (s *sharedServerContextSuite) TestConfigNoController(c *gc.C) {
    96  	s.config.controller = nil
    97  	err := s.config.validate()
    98  	c.Check(err, jc.Satisfies, errors.IsNotValid)
    99  	c.Check(err, gc.ErrorMatches, "nil controller not valid")
   100  }
   101  
   102  func (s *sharedServerContextSuite) TestConfigNoMultiwatcherFactory(c *gc.C) {
   103  	s.config.multiwatcherFactory = nil
   104  	err := s.config.validate()
   105  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   106  	c.Check(err, gc.ErrorMatches, "nil multiwatcherFactory not valid")
   107  }
   108  
   109  func (s *sharedServerContextSuite) TestConfigNoHub(c *gc.C) {
   110  	s.config.centralHub = nil
   111  	err := s.config.validate()
   112  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   113  	c.Check(err, gc.ErrorMatches, "nil centralHub not valid")
   114  }
   115  
   116  func (s *sharedServerContextSuite) TestConfigNoPresence(c *gc.C) {
   117  	s.config.presence = nil
   118  	err := s.config.validate()
   119  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   120  	c.Check(err, gc.ErrorMatches, "nil presence not valid")
   121  }
   122  
   123  func (s *sharedServerContextSuite) TestConfigNoLeaseManager(c *gc.C) {
   124  	s.config.leaseManager = nil
   125  	err := s.config.validate()
   126  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   127  	c.Check(err, gc.ErrorMatches, "nil leaseManager not valid")
   128  }
   129  
   130  func (s *sharedServerContextSuite) TestConfigNoControllerconfig(c *gc.C) {
   131  	s.config.controllerConfig = nil
   132  	err := s.config.validate()
   133  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   134  	c.Check(err, gc.ErrorMatches, "nil controllerConfig not valid")
   135  }
   136  
   137  func (s *sharedServerContextSuite) TestNewCallsConfigValidate(c *gc.C) {
   138  	s.config.statePool = nil
   139  	ctx, err := newSharedServerContext(s.config)
   140  	c.Check(err, jc.Satisfies, errors.IsNotValid)
   141  	c.Check(err, gc.ErrorMatches, "nil statePool not valid")
   142  	c.Check(ctx, gc.IsNil)
   143  }
   144  
   145  func (s *sharedServerContextSuite) TestValidConfig(c *gc.C) {
   146  	ctx, err := newSharedServerContext(s.config)
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	// Normally you wouldn't directly access features.
   149  	c.Assert(ctx.features, gc.HasLen, 0)
   150  	ctx.Close()
   151  }
   152  
   153  func (s *sharedServerContextSuite) newContext(c *gc.C) *sharedServerContext {
   154  	ctx, err := newSharedServerContext(s.config)
   155  	c.Assert(err, jc.ErrorIsNil)
   156  	s.AddCleanup(func(*gc.C) { ctx.Close() })
   157  	return ctx
   158  }
   159  
   160  type stubHub struct {
   161  	*pubsub.StructuredHub
   162  
   163  	published []string
   164  }
   165  
   166  func (s *stubHub) Publish(topic string, data interface{}) (func(), error) {
   167  	s.published = append(s.published, topic)
   168  	return func() {}, nil
   169  }
   170  
   171  func (s *sharedServerContextSuite) TestControllerConfigChanged(c *gc.C) {
   172  	stub := &stubHub{StructuredHub: s.hub}
   173  	s.config.centralHub = stub
   174  	ctx := s.newContext(c)
   175  
   176  	msg := controller.ConfigChangedMessage{
   177  		Config: corecontroller.Config{
   178  			corecontroller.Features: []string{"foo", "bar"},
   179  		},
   180  	}
   181  
   182  	done, err := s.hub.Publish(controller.ConfigChanged, msg)
   183  	c.Assert(err, jc.ErrorIsNil)
   184  
   185  	select {
   186  	case <-pubsub.Wait(done):
   187  	case <-time.After(testing.LongWait):
   188  		c.Fatalf("handler didn't")
   189  	}
   190  
   191  	c.Check(ctx.featureEnabled("foo"), jc.IsTrue)
   192  	c.Check(ctx.featureEnabled("bar"), jc.IsTrue)
   193  	c.Check(ctx.featureEnabled("baz"), jc.IsFalse)
   194  	c.Check(stub.published, gc.HasLen, 0)
   195  }
   196  
   197  type noopRegisterer struct {
   198  	prometheus.Registerer
   199  }
   200  
   201  func (noopRegisterer) Register(prometheus.Collector) error {
   202  	return nil
   203  }
   204  
   205  func (noopRegisterer) Unregister(prometheus.Collector) bool {
   206  	return true
   207  }