github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/httpserver/manifold_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package httpserver_test 5 6 import ( 7 "crypto/tls" 8 "time" 9 10 "github.com/juju/clock/testclock" 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 mgotesting "github.com/juju/mgo/v3/testing" 14 "github.com/juju/pubsub/v2" 15 "github.com/juju/testing" 16 jc "github.com/juju/testing/checkers" 17 "github.com/juju/worker/v3" 18 "github.com/juju/worker/v3/dependency" 19 dt "github.com/juju/worker/v3/dependency/testing" 20 "github.com/juju/worker/v3/workertest" 21 gc "gopkg.in/check.v1" 22 23 "github.com/juju/juju/apiserver/apiserverhttp" 24 "github.com/juju/juju/controller" 25 "github.com/juju/juju/pki" 26 pkitest "github.com/juju/juju/pki/test" 27 "github.com/juju/juju/state" 28 statetesting "github.com/juju/juju/state/testing" 29 "github.com/juju/juju/worker/httpserver" 30 ) 31 32 type ManifoldSuite struct { 33 testing.IsolationSuite 34 statetesting.StateSuite 35 36 authority pki.Authority 37 config httpserver.ManifoldConfig 38 manifold dependency.Manifold 39 context dependency.Context 40 state stubStateTracker 41 hub *pubsub.StructuredHub 42 mux *apiserverhttp.Mux 43 clock *testclock.Clock 44 prometheusRegisterer stubPrometheusRegisterer 45 tlsConfig *tls.Config 46 controllerConfig controller.Config 47 48 stub testing.Stub 49 } 50 51 var _ = gc.Suite(&ManifoldSuite{}) 52 53 func (s *ManifoldSuite) SetUpTest(c *gc.C) { 54 s.IsolationSuite.SetUpTest(c) 55 56 authority, err := pkitest.NewTestAuthority() 57 c.Assert(err, jc.ErrorIsNil) 58 s.authority = authority 59 60 s.mux = &apiserverhttp.Mux{} 61 s.hub = pubsub.NewStructuredHub(nil) 62 s.clock = testclock.NewClock(time.Now()) 63 s.prometheusRegisterer = stubPrometheusRegisterer{} 64 s.tlsConfig = &tls.Config{} 65 s.controllerConfig = controller.Config(map[string]interface{}{ 66 "api-port": 1024, 67 "controller-api-port": 2048, 68 "api-port-open-delay": "5s", 69 }) 70 s.stub.ResetCalls() 71 72 s.context = s.newContext(nil) 73 s.config = httpserver.ManifoldConfig{ 74 AgentName: "machine-42", 75 AuthorityName: "authority", 76 HubName: "hub", 77 StateName: "state", 78 MuxName: "mux", 79 APIServerName: "api-server", 80 Clock: s.clock, 81 PrometheusRegisterer: &s.prometheusRegisterer, 82 MuxShutdownWait: 1 * time.Minute, 83 LogDir: "log-dir", 84 GetControllerConfig: s.getControllerConfig, 85 NewTLSConfig: s.newTLSConfig, 86 NewWorker: s.newWorker, 87 Logger: loggo.GetLogger("test"), 88 } 89 s.manifold = httpserver.Manifold(s.config) 90 s.StateSuite.SetUpTest(c) 91 s.state = stubStateTracker{ 92 pool: s.StatePool, 93 } 94 } 95 96 func (s *ManifoldSuite) SetUpSuite(c *gc.C) { 97 s.IsolationSuite.SetUpSuite(c) 98 99 mgotesting.MgoServer.EnableReplicaSet = true 100 err := mgotesting.MgoServer.Start(nil) 101 c.Assert(err, jc.ErrorIsNil) 102 s.IsolationSuite.AddCleanup(func(*gc.C) { mgotesting.MgoServer.Destroy() }) 103 104 s.StateSuite.SetUpSuite(c) 105 } 106 107 func (s *ManifoldSuite) TearDownSuite(c *gc.C) { 108 s.StateSuite.TearDownSuite(c) 109 s.IsolationSuite.TearDownSuite(c) 110 } 111 112 func (s *ManifoldSuite) TearDownTest(c *gc.C) { 113 s.StateSuite.TearDownTest(c) 114 s.IsolationSuite.TearDownTest(c) 115 } 116 117 func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context { 118 resources := map[string]interface{}{ 119 "authority": s.authority, 120 "state": &s.state, 121 "hub": s.hub, 122 "mux": s.mux, 123 "raft-transport": nil, 124 "api-server": nil, 125 } 126 for k, v := range overlay { 127 resources[k] = v 128 } 129 return dt.StubContext(nil, resources) 130 } 131 132 func (s *ManifoldSuite) getControllerConfig(st *state.State) (controller.Config, error) { 133 s.stub.MethodCall(s, "GetControllerConfig", st) 134 if err := s.stub.NextErr(); err != nil { 135 return nil, err 136 } 137 return s.controllerConfig, nil 138 } 139 140 func (s *ManifoldSuite) newTLSConfig( 141 st *state.State, 142 _ httpserver.SNIGetterFunc, 143 _ httpserver.Logger, 144 ) (*tls.Config, error) { 145 s.stub.MethodCall(s, "NewTLSConfig", st) 146 if err := s.stub.NextErr(); err != nil { 147 return nil, err 148 } 149 return s.tlsConfig, nil 150 } 151 152 func (s *ManifoldSuite) newWorker(config httpserver.Config) (worker.Worker, error) { 153 s.stub.MethodCall(s, "NewWorker", config) 154 if err := s.stub.NextErr(); err != nil { 155 return nil, err 156 } 157 return worker.NewRunner(worker.RunnerParams{}), nil 158 } 159 160 var expectedInputs = []string{ 161 "authority", 162 "state", 163 "mux", 164 "hub", 165 "api-server", 166 } 167 168 func (s *ManifoldSuite) TestInputs(c *gc.C) { 169 c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs) 170 } 171 172 func (s *ManifoldSuite) TestMissingInputs(c *gc.C) { 173 for _, input := range expectedInputs { 174 context := s.newContext(map[string]interface{}{ 175 input: dependency.ErrMissing, 176 }) 177 _, err := s.manifold.Start(context) 178 c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing) 179 } 180 } 181 182 func (s *ManifoldSuite) TestStart(c *gc.C) { 183 w := s.startWorkerClean(c) 184 workertest.CleanKill(c, w) 185 186 s.stub.CheckCallNames(c, "NewTLSConfig", "GetControllerConfig", "NewWorker") 187 newWorkerArgs := s.stub.Calls()[2].Args 188 c.Assert(newWorkerArgs, gc.HasLen, 1) 189 c.Assert(newWorkerArgs[0], gc.FitsTypeOf, httpserver.Config{}) 190 config := newWorkerArgs[0].(httpserver.Config) 191 192 c.Assert(config, jc.DeepEquals, httpserver.Config{ 193 AgentName: "machine-42", 194 Clock: s.clock, 195 PrometheusRegisterer: &s.prometheusRegisterer, 196 Hub: s.hub, 197 TLSConfig: s.tlsConfig, 198 Mux: s.mux, 199 APIPort: 1024, 200 APIPortOpenDelay: 5 * time.Second, 201 ControllerAPIPort: 2048, 202 MuxShutdownWait: 1 * time.Minute, 203 LogDir: "log-dir", 204 Logger: s.config.Logger, 205 }) 206 } 207 208 func (s *ManifoldSuite) TestValidate(c *gc.C) { 209 type test struct { 210 f func(*httpserver.ManifoldConfig) 211 expect string 212 } 213 tests := []test{{ 214 func(cfg *httpserver.ManifoldConfig) { cfg.AgentName = "" }, 215 "empty AgentName not valid", 216 }, { 217 func(cfg *httpserver.ManifoldConfig) { cfg.AuthorityName = "" }, 218 "empty AuthorityName not valid", 219 }, { 220 func(cfg *httpserver.ManifoldConfig) { cfg.StateName = "" }, 221 "empty StateName not valid", 222 }, { 223 func(cfg *httpserver.ManifoldConfig) { cfg.MuxName = "" }, 224 "empty MuxName not valid", 225 }, { 226 func(cfg *httpserver.ManifoldConfig) { cfg.MuxShutdownWait = 0 }, 227 "MuxShutdownWait 0s not valid", 228 }, { 229 func(cfg *httpserver.ManifoldConfig) { cfg.LogDir = "" }, 230 "empty LogDir not valid", 231 }, { 232 func(cfg *httpserver.ManifoldConfig) { cfg.APIServerName = "" }, 233 "empty APIServerName not valid", 234 }, { 235 func(cfg *httpserver.ManifoldConfig) { cfg.PrometheusRegisterer = nil }, 236 "nil PrometheusRegisterer not valid", 237 }, { 238 func(cfg *httpserver.ManifoldConfig) { cfg.GetControllerConfig = nil }, 239 "nil GetControllerConfig not valid", 240 }, { 241 func(cfg *httpserver.ManifoldConfig) { cfg.NewTLSConfig = nil }, 242 "nil NewTLSConfig not valid", 243 }, { 244 func(cfg *httpserver.ManifoldConfig) { cfg.NewWorker = nil }, 245 "nil NewWorker not valid", 246 }} 247 for i, test := range tests { 248 c.Logf("test #%d (%s)", i, test.expect) 249 config := s.config 250 test.f(&config) 251 manifold := httpserver.Manifold(config) 252 w, err := manifold.Start(s.context) 253 workertest.CheckNilOrKill(c, w) 254 c.Check(err, gc.ErrorMatches, test.expect) 255 } 256 } 257 258 func (s *ManifoldSuite) TestStopWorkerClosesState(c *gc.C) { 259 w := s.startWorkerClean(c) 260 defer workertest.CleanKill(c, w) 261 262 s.state.CheckCallNames(c, "Use") 263 264 workertest.CleanKill(c, w) 265 s.state.CheckCallNames(c, "Use", "Done") 266 } 267 268 func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker { 269 w, err := s.manifold.Start(s.context) 270 c.Assert(err, jc.ErrorIsNil) 271 workertest.CheckAlive(c, w) 272 return w 273 }