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