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