github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/lease/manifold/manifold_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package manifold_test 5 6 import ( 7 "io" 8 "time" 9 10 "github.com/juju/clock/testclock" 11 "github.com/juju/errors" 12 "github.com/juju/loggo" 13 "github.com/juju/names/v5" 14 "github.com/juju/testing" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/worker/v3" 17 "github.com/juju/worker/v3/dependency" 18 dt "github.com/juju/worker/v3/dependency/testing" 19 "github.com/prometheus/client_golang/prometheus" 20 "go.uber.org/mock/gomock" 21 gc "gopkg.in/check.v1" 22 23 "github.com/juju/juju/agent" 24 "github.com/juju/juju/api" 25 coredatabase "github.com/juju/juju/core/database" 26 corelease "github.com/juju/juju/core/lease" 27 statetesting "github.com/juju/juju/state/testing" 28 "github.com/juju/juju/worker/lease" 29 leasemanager "github.com/juju/juju/worker/lease/manifold" 30 ) 31 32 type manifoldSuite struct { 33 statetesting.StateSuite 34 35 context dependency.Context 36 manifold dependency.Manifold 37 38 agent *mockAgent 39 clock *testclock.Clock 40 dbAccessor stubDBGetter 41 42 logger loggo.Logger 43 metrics prometheus.Registerer 44 45 worker worker.Worker 46 trackedDB coredatabase.TrackedDB 47 store *lease.Store 48 49 stub testing.Stub 50 } 51 52 var _ = gc.Suite(&manifoldSuite{}) 53 54 func (s *manifoldSuite) SetUpTest(c *gc.C) { 55 ctrl := gomock.NewController(c) 56 defer ctrl.Finish() 57 58 s.StateSuite.SetUpTest(c) 59 60 s.stub.ResetCalls() 61 62 s.trackedDB = NewMockTrackedDB(ctrl) 63 64 s.agent = &mockAgent{conf: mockAgentConfig{ 65 uuid: "controller-uuid", 66 apiInfo: &api.Info{}, 67 }} 68 s.clock = testclock.NewClock(time.Now()) 69 s.dbAccessor = stubDBGetter{s.trackedDB} 70 71 s.logger = loggo.GetLogger("lease.manifold_test") 72 registerer := struct{ prometheus.Registerer }{} 73 s.metrics = ®isterer 74 75 s.worker = &mockWorker{} 76 s.store = &lease.Store{} 77 78 s.context = s.newContext(nil) 79 s.manifold = leasemanager.Manifold(leasemanager.ManifoldConfig{ 80 AgentName: "agent", 81 ClockName: "clock", 82 DBAccessorName: "db-accessor", 83 Logger: &s.logger, 84 PrometheusRegisterer: s.metrics, 85 NewWorker: s.newWorker, 86 NewStore: s.newStore, 87 }) 88 } 89 90 func (s *manifoldSuite) newContext(overlay map[string]interface{}) dependency.Context { 91 resources := map[string]interface{}{ 92 "agent": s.agent, 93 "clock": s.clock, 94 "db-accessor": s.dbAccessor, 95 } 96 for k, v := range overlay { 97 resources[k] = v 98 } 99 return dt.StubContext(nil, resources) 100 } 101 102 func (s *manifoldSuite) newWorker(config lease.ManagerConfig) (worker.Worker, error) { 103 s.stub.MethodCall(s, "NewWorker", config) 104 if err := s.stub.NextErr(); err != nil { 105 return nil, err 106 } 107 return s.worker, nil 108 } 109 110 func (s *manifoldSuite) newStore(config lease.StoreConfig) *lease.Store { 111 s.stub.MethodCall(s, "NewStore", config) 112 return s.store 113 } 114 115 var expectedInputs = []string{ 116 "agent", "clock", "db-accessor", 117 } 118 119 func (s *manifoldSuite) TestInputs(c *gc.C) { 120 c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs) 121 } 122 123 func (s *manifoldSuite) TestMissingInputs(c *gc.C) { 124 for _, input := range expectedInputs { 125 ctx := s.newContext(map[string]interface{}{ 126 input: dependency.ErrMissing, 127 }) 128 _, err := s.manifold.Start(ctx) 129 c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing) 130 } 131 } 132 133 func (s *manifoldSuite) TestStart(c *gc.C) { 134 _, err := s.manifold.Start(s.context) 135 c.Assert(err, jc.ErrorIsNil) 136 137 s.stub.CheckCallNames(c, "NewStore", "NewWorker") 138 139 args := s.stub.Calls()[0].Args 140 c.Assert(args, gc.HasLen, 1) 141 c.Assert(args[0], gc.FitsTypeOf, lease.StoreConfig{}) 142 143 storeConfig := args[0].(lease.StoreConfig) 144 145 c.Assert(storeConfig, gc.DeepEquals, lease.StoreConfig{ 146 TrackedDB: s.trackedDB, 147 Logger: &s.logger, 148 }) 149 150 args = s.stub.Calls()[1].Args 151 c.Assert(args, gc.HasLen, 1) 152 c.Assert(args[0], gc.FitsTypeOf, lease.ManagerConfig{}) 153 config := args[0].(lease.ManagerConfig) 154 155 secretary, err := config.Secretary(corelease.SingularControllerNamespace) 156 c.Assert(err, jc.ErrorIsNil) 157 // Check that this secretary knows the controller uuid. 158 err = secretary.CheckLease(corelease.Key{Lease: "controller-uuid"}) 159 c.Assert(err, jc.ErrorIsNil) 160 config.Secretary = nil 161 162 c.Assert(config, jc.DeepEquals, lease.ManagerConfig{ 163 Store: s.store, 164 Clock: s.clock, 165 Logger: &s.logger, 166 MaxSleep: time.Minute, 167 EntityUUID: "controller-uuid", 168 PrometheusRegisterer: s.metrics, 169 }) 170 } 171 172 func (s *manifoldSuite) TestOutput(c *gc.C) { 173 s.worker = &lease.Manager{} 174 w, err := s.manifold.Start(s.context) 175 c.Assert(err, jc.ErrorIsNil) 176 177 var manager corelease.Manager 178 err = s.manifold.Output(w, &manager) 179 c.Assert(err, jc.ErrorIsNil) 180 c.Assert(manager, gc.Equals, s.worker) 181 182 var other io.Writer 183 err = s.manifold.Output(w, &other) 184 c.Assert(err, gc.ErrorMatches, `expected output of type \*core/lease.Manager, got \*io.Writer`) 185 } 186 187 type mockAgent struct { 188 agent.Agent 189 conf mockAgentConfig 190 } 191 192 func (ma *mockAgent) CurrentConfig() agent.Config { 193 return &ma.conf 194 } 195 196 type mockAgentConfig struct { 197 agent.Config 198 uuid string 199 apiInfo *api.Info 200 } 201 202 func (c *mockAgentConfig) Controller() names.ControllerTag { 203 return names.NewControllerTag(c.uuid) 204 } 205 206 func (c *mockAgentConfig) APIInfo() (*api.Info, bool) { 207 return c.apiInfo, true 208 } 209 210 type mockWorker struct{} 211 212 func (*mockWorker) Kill() {} 213 func (*mockWorker) Wait() error { 214 return nil 215 } 216 217 type stubDBGetter struct { 218 trackedDB coredatabase.TrackedDB 219 } 220 221 func (s stubDBGetter) GetDB(name string) (coredatabase.TrackedDB, error) { 222 if name != "controller" { 223 return nil, errors.Errorf(`expected a request for "controller" DB; got %q`, name) 224 } 225 return s.trackedDB, nil 226 }