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 }