github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/apicaller/manifold_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apicaller_test 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/loggo" 9 "github.com/juju/names/v5" 10 "github.com/juju/testing" 11 jc "github.com/juju/testing/checkers" 12 "github.com/juju/worker/v3" 13 "github.com/juju/worker/v3/dependency" 14 dt "github.com/juju/worker/v3/dependency/testing" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/agent" 18 "github.com/juju/juju/api" 19 "github.com/juju/juju/api/base" 20 coretesting "github.com/juju/juju/testing" 21 "github.com/juju/juju/worker/apicaller" 22 ) 23 24 type ManifoldSuite struct { 25 testing.IsolationSuite 26 testing.Stub 27 28 manifold dependency.Manifold 29 manifoldConfig apicaller.ManifoldConfig 30 agent *mockAgent 31 conn *mockConn 32 context dependency.Context 33 } 34 35 var _ = gc.Suite(&ManifoldSuite{}) 36 37 func (s *ManifoldSuite) SetUpTest(c *gc.C) { 38 s.IsolationSuite.SetUpTest(c) 39 s.Stub = testing.Stub{} 40 s.manifoldConfig = apicaller.ManifoldConfig{ 41 AgentName: "agent-name", 42 APIConfigWatcherName: "api-config-watcher-name", 43 APIOpen: func(*api.Info, api.DialOpts) (api.Connection, error) { 44 panic("just a fake") 45 }, 46 NewConnection: func(a agent.Agent, apiOpen api.OpenFunc, logger apicaller.Logger) (api.Connection, error) { 47 c.Check(apiOpen, gc.NotNil) // uncomparable 48 c.Check(logger, gc.NotNil) // uncomparable 49 s.AddCall("NewConnection", a) 50 if err := s.NextErr(); err != nil { 51 return nil, err 52 } 53 return s.conn, nil 54 }, 55 Filter: func(err error) error { 56 panic(err) 57 }, 58 Logger: loggo.GetLogger("test"), 59 } 60 s.manifold = apicaller.Manifold(s.manifoldConfig) 61 checkFilter := func() { 62 s.manifold.Filter(errors.New("arrgh")) 63 } 64 c.Check(checkFilter, gc.PanicMatches, "arrgh") 65 66 s.agent = &mockAgent{ 67 stub: &s.Stub, 68 model: coretesting.ModelTag, 69 entity: names.NewMachineTag("42"), 70 } 71 s.context = dt.StubContext(nil, map[string]interface{}{ 72 "agent-name": s.agent, 73 }) 74 75 // Watch out for this: it uses its own Stub because Close calls 76 // are made from the worker's loop goroutine. You should make 77 // sure to stop the worker before checking the mock conn's calls. 78 s.conn = &mockConn{ 79 stub: &testing.Stub{}, 80 broken: make(chan struct{}), 81 } 82 } 83 84 func (s *ManifoldSuite) TestInputsOptionalConfigPropertiesUnset(c *gc.C) { 85 s.manifoldConfig.APIConfigWatcherName = "" 86 c.Check(apicaller.Manifold(s.manifoldConfig).Inputs, jc.DeepEquals, []string{ 87 "agent-name", 88 }) 89 } 90 91 func (s *ManifoldSuite) TestInputs(c *gc.C) { 92 c.Check(s.manifold.Inputs, jc.DeepEquals, []string{ 93 "agent-name", 94 "api-config-watcher-name", 95 }) 96 } 97 98 func (s *ManifoldSuite) TestStartMissingAgent(c *gc.C) { 99 context := dt.StubContext(nil, map[string]interface{}{ 100 "agent-name": dependency.ErrMissing, 101 }) 102 103 worker, err := s.manifold.Start(context) 104 c.Check(worker, gc.IsNil) 105 c.Check(err, gc.Equals, dependency.ErrMissing) 106 s.CheckCalls(c, nil) 107 } 108 109 func (s *ManifoldSuite) TestStartCannotOpenAPI(c *gc.C) { 110 s.SetErrors(errors.New("no api for you")) 111 112 worker, err := s.manifold.Start(s.context) 113 c.Check(worker, gc.IsNil) 114 c.Check(err, gc.ErrorMatches, `\[deadbe\] "machine-42" cannot open api: no api for you`) 115 s.CheckCalls(c, []testing.StubCall{{ 116 FuncName: "NewConnection", 117 Args: []interface{}{s.agent}, 118 }}) 119 } 120 121 func (s *ManifoldSuite) TestStartSuccess(c *gc.C) { 122 worker, err := s.manifold.Start(s.context) 123 c.Check(err, jc.ErrorIsNil) 124 defer assertStop(c, worker) 125 s.CheckCalls(c, []testing.StubCall{{ 126 FuncName: "NewConnection", 127 Args: []interface{}{s.agent}, 128 }}) 129 } 130 131 func (s *ManifoldSuite) setupWorkerTest(c *gc.C) worker.Worker { 132 w, err := s.manifold.Start(s.context) 133 c.Assert(err, jc.ErrorIsNil) 134 s.AddCleanup(func(c *gc.C) { w.Kill() }) 135 return w 136 } 137 138 func (s *ManifoldSuite) TestKillWorkerClosesConnection(c *gc.C) { 139 worker := s.setupWorkerTest(c) 140 assertStop(c, worker) 141 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 142 FuncName: "Close", 143 }}) 144 } 145 146 func (s *ManifoldSuite) TestKillWorkerReportsCloseErr(c *gc.C) { 147 s.conn.stub.SetErrors(errors.New("bad plumbing")) 148 worker := s.setupWorkerTest(c) 149 150 assertStopError(c, worker, "bad plumbing") 151 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 152 FuncName: "Close", 153 }}) 154 } 155 156 func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithCloseErr(c *gc.C) { 157 s.conn.stub.SetErrors(errors.New("bad plumbing")) 158 worker := s.setupWorkerTest(c) 159 160 close(s.conn.broken) 161 err := worker.Wait() 162 c.Check(err, gc.ErrorMatches, "bad plumbing") 163 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 164 FuncName: "Close", 165 }}) 166 } 167 168 func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithFallbackErr(c *gc.C) { 169 worker := s.setupWorkerTest(c) 170 171 close(s.conn.broken) 172 err := worker.Wait() 173 c.Check(err, gc.ErrorMatches, "api connection broken unexpectedly") 174 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 175 FuncName: "Close", 176 }}) 177 } 178 179 func (s *ManifoldSuite) TestOutputSuccess(c *gc.C) { 180 worker := s.setupWorkerTest(c) 181 182 var apicaller base.APICaller 183 err := s.manifold.Output(worker, &apicaller) 184 c.Check(err, jc.ErrorIsNil) 185 c.Check(apicaller, gc.Equals, s.conn) 186 187 var conn api.Connection 188 err = s.manifold.Output(worker, &conn) 189 c.Check(err, jc.ErrorIsNil) 190 c.Check(conn, gc.Equals, s.conn) 191 } 192 193 func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) { 194 var apicaller base.APICaller 195 err := s.manifold.Output(dummyWorker{}, &apicaller) 196 c.Check(apicaller, gc.IsNil) 197 c.Check(err.Error(), gc.Equals, "in should be a *apicaller.apiConnWorker; got apicaller_test.dummyWorker") 198 } 199 200 func (s *ManifoldSuite) TestOutputBadTarget(c *gc.C) { 201 worker := s.setupWorkerTest(c) 202 203 var apicaller interface{} 204 err := s.manifold.Output(worker, &apicaller) 205 c.Check(apicaller, gc.IsNil) 206 c.Check(err.Error(), gc.Equals, "out should be *base.APICaller or *api.Connection; got *interface {}") 207 }