github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/metrics/sender/manifold_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package sender_test 5 6 import ( 7 "context" 8 "net/http" 9 "net/url" 10 "os" 11 "path/filepath" 12 13 "github.com/juju/errors" 14 "github.com/juju/names/v5" 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 gc "gopkg.in/check.v1" 21 "gopkg.in/httprequest.v1" 22 23 "github.com/juju/juju/agent" 24 "github.com/juju/juju/api/agent/metricsadder" 25 "github.com/juju/juju/api/base" 26 "github.com/juju/juju/worker/metrics/sender" 27 "github.com/juju/juju/worker/metrics/spool" 28 ) 29 30 type ManifoldSuite struct { 31 testing.IsolationSuite 32 factory spool.MetricFactory 33 apiCaller *stubAPICaller 34 manifold dependency.Manifold 35 resources dt.StubResources 36 } 37 38 var _ = gc.Suite(&ManifoldSuite{}) 39 40 func (s *ManifoldSuite) SetUpTest(c *gc.C) { 41 spoolDir := c.MkDir() 42 s.IsolationSuite.SetUpTest(c) 43 s.factory = &stubMetricFactory{ 44 &testing.Stub{}, 45 spoolDir, 46 } 47 48 testAPIClient := func(apiCaller base.APICaller) metricsadder.MetricsAdderClient { 49 return newTestAPIMetricSender() 50 } 51 s.PatchValue(&sender.NewMetricAdderClient, testAPIClient) 52 53 s.manifold = sender.Manifold(sender.ManifoldConfig{ 54 AgentName: "agent", 55 APICallerName: "api-caller", 56 MetricSpoolName: "metric-spool", 57 }) 58 59 dataDir := c.MkDir() 60 // create unit agent base dir so that hooks can run. 61 err := os.MkdirAll(filepath.Join(dataDir, "agents", "unit-u-0"), 0777) 62 c.Assert(err, jc.ErrorIsNil) 63 64 s.apiCaller = &stubAPICaller{&testing.Stub{}} 65 s.resources = dt.StubResources{ 66 "agent": dt.NewStubResource(&dummyAgent{dataDir: dataDir}), 67 "api-caller": dt.NewStubResource(s.apiCaller), 68 "metric-spool": dt.NewStubResource(s.factory), 69 } 70 } 71 72 func (s *ManifoldSuite) TestInputs(c *gc.C) { 73 c.Check(s.manifold.Inputs, jc.DeepEquals, []string{"agent", "api-caller", "metric-spool"}) 74 } 75 76 func (s *ManifoldSuite) TestStartMissingAPICaller(c *gc.C) { 77 context := dt.StubContext(nil, map[string]interface{}{ 78 "api-caller": dependency.ErrMissing, 79 "metric-spool": s.factory, 80 }) 81 worker, err := s.manifold.Start(context) 82 c.Check(worker, gc.IsNil) 83 c.Check(err, gc.ErrorMatches, dependency.ErrMissing.Error()) 84 } 85 86 func (s *ManifoldSuite) TestStartMissingAgent(c *gc.C) { 87 context := dt.StubContext(nil, map[string]interface{}{ 88 "agent": dependency.ErrMissing, 89 "api-caller": &stubAPICaller{&testing.Stub{}}, 90 "metric-spool": s.factory, 91 }) 92 worker, err := s.manifold.Start(context) 93 c.Check(worker, gc.IsNil) 94 c.Check(err, gc.ErrorMatches, dependency.ErrMissing.Error()) 95 } 96 97 func (s *ManifoldSuite) TestStartSuccess(c *gc.C) { 98 s.setupWorkerTest(c) 99 } 100 101 func (s *ManifoldSuite) setupWorkerTest(c *gc.C) worker.Worker { 102 worker, err := s.manifold.Start(s.resources.Context()) 103 c.Check(err, jc.ErrorIsNil) 104 s.AddCleanup(func(c *gc.C) { 105 worker.Kill() 106 err := worker.Wait() 107 c.Check(err, jc.ErrorIsNil) 108 }) 109 return worker 110 } 111 112 type mockListener struct { 113 testing.Stub 114 spool.ConnectionHandler 115 } 116 117 // Stop implements the stopper interface. 118 func (l *mockListener) Stop() error { 119 l.AddCall("Stop") 120 return nil 121 } 122 123 func (s *ManifoldSuite) TestWorkerErrorStopsSender(c *gc.C) { 124 listener := &mockListener{} 125 s.PatchValue(sender.NewListener, sender.NewListenerFunc(listener)) 126 127 s.apiCaller.SetErrors(errors.New("blah")) 128 129 worker, err := s.manifold.Start(s.resources.Context()) 130 c.Assert(err, jc.ErrorIsNil) 131 c.Assert(worker, gc.NotNil) 132 err = worker.Wait() 133 c.Assert(err, gc.ErrorMatches, ".*blah") 134 listener.CheckCallNames(c, "Stop") 135 } 136 137 var _ base.APICaller = (*stubAPICaller)(nil) 138 139 type stubAPICaller struct { 140 *testing.Stub 141 } 142 143 func (s *stubAPICaller) APICall(objType string, version int, id, request string, params, response interface{}) error { 144 s.MethodCall(s, "APICall", objType, version, id, request, params, response) 145 return s.NextErr() 146 } 147 148 func (s *stubAPICaller) BestFacadeVersion(facade string) int { 149 s.MethodCall(s, "BestFacadeVersion", facade) 150 return 42 151 } 152 153 func (s *stubAPICaller) ModelTag() (names.ModelTag, bool) { 154 s.MethodCall(s, "ModelTag") 155 return names.NewModelTag("foobar"), true 156 } 157 158 func (s *stubAPICaller) ConnectStream(string, url.Values) (base.Stream, error) { 159 panic("should not be called") 160 } 161 162 func (s *stubAPICaller) ConnectControllerStream(string, url.Values, http.Header) (base.Stream, error) { 163 panic("should not be called") 164 } 165 166 func (s *stubAPICaller) HTTPClient() (*httprequest.Client, error) { 167 panic("should not be called") 168 } 169 170 func (s *stubAPICaller) RootHTTPClient() (*httprequest.Client, error) { 171 panic("should not be called") 172 } 173 174 func (s *stubAPICaller) Context() context.Context { 175 return context.Background() 176 } 177 178 func (s *stubAPICaller) BakeryClient() base.MacaroonDischarger { 179 panic("should not be called") 180 } 181 182 type dummyAgent struct { 183 agent.Agent 184 dataDir string 185 } 186 187 func (a dummyAgent) CurrentConfig() agent.Config { 188 return &dummyAgentConfig{dataDir: a.dataDir} 189 } 190 191 type dummyAgentConfig struct { 192 agent.Config 193 dataDir string 194 } 195 196 // Tag implements agent.AgentConfig. 197 func (ac dummyAgentConfig) Tag() names.Tag { 198 return names.NewUnitTag("u/0") 199 } 200 201 // DataDir implements agent.AgentConfig. 202 func (ac dummyAgentConfig) DataDir() string { 203 return ac.dataDir 204 }