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