github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/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/names" 9 "github.com/juju/testing" 10 jc "github.com/juju/testing/checkers" 11 gc "gopkg.in/check.v1" 12 13 "github.com/juju/juju/agent" 14 "github.com/juju/juju/api" 15 "github.com/juju/juju/api/base" 16 coretesting "github.com/juju/juju/testing" 17 "github.com/juju/juju/worker" 18 "github.com/juju/juju/worker/apicaller" 19 "github.com/juju/juju/worker/dependency" 20 dt "github.com/juju/juju/worker/dependency/testing" 21 ) 22 23 type ManifoldSuite struct { 24 testing.IsolationSuite 25 testing.Stub 26 manifold dependency.Manifold 27 agent *mockAgent 28 gate *mockGate 29 conn *mockConn 30 getResource dependency.GetResourceFunc 31 } 32 33 var _ = gc.Suite(&ManifoldSuite{}) 34 35 func (s *ManifoldSuite) SetUpTest(c *gc.C) { 36 s.IsolationSuite.SetUpTest(c) 37 s.Stub = testing.Stub{} 38 s.manifold = apicaller.Manifold(apicaller.ManifoldConfig{ 39 AgentName: "agent-name", 40 APIInfoGateName: "api-info-gate-name", 41 }) 42 43 s.agent = &mockAgent{ 44 stub: &s.Stub, 45 env: coretesting.EnvironmentTag, 46 } 47 s.gate = &mockGate{ 48 stub: &s.Stub, 49 } 50 s.getResource = dt.StubGetResource(dt.StubResources{ 51 "agent-name": dt.StubResource{Output: s.agent}, 52 "api-info-gate-name": dt.StubResource{Output: s.gate}, 53 }) 54 55 // Watch out for this: it uses its own Stub because Close calls are made from 56 // the worker's loop goroutine. You should make sure to stop the worker before 57 // checking the mock conn's calls (unless you know the connection will outlive 58 // the test -- see setupMutatorTest). 59 s.conn = &mockConn{ 60 stub: &testing.Stub{}, 61 broken: make(chan struct{}), 62 } 63 s.PatchValue(apicaller.OpenConnection, func(a agent.Agent) (api.Connection, error) { 64 s.AddCall("openConnection", a) 65 if err := s.NextErr(); err != nil { 66 return nil, err 67 } 68 return s.conn, nil 69 }) 70 } 71 72 func (s *ManifoldSuite) TestInputs(c *gc.C) { 73 c.Check(s.manifold.Inputs, jc.DeepEquals, []string{"agent-name", "api-info-gate-name"}) 74 } 75 76 func (s *ManifoldSuite) TestStartMissingAgent(c *gc.C) { 77 getResource := dt.StubGetResource(dt.StubResources{ 78 "agent-name": dt.StubResource{Error: dependency.ErrMissing}, 79 "api-info-gate-name": dt.StubResource{Output: s.gate}, 80 }) 81 82 worker, err := s.manifold.Start(getResource) 83 c.Check(worker, gc.IsNil) 84 c.Check(err, gc.Equals, dependency.ErrMissing) 85 s.CheckCalls(c, nil) 86 } 87 88 func (s *ManifoldSuite) TestStartMissingGate(c *gc.C) { 89 getResource := dt.StubGetResource(dt.StubResources{ 90 "agent-name": dt.StubResource{Output: s.agent}, 91 "api-info-gate-name": dt.StubResource{Error: dependency.ErrMissing}, 92 }) 93 94 worker, err := s.manifold.Start(getResource) 95 c.Check(worker, gc.IsNil) 96 c.Check(err, gc.Equals, dependency.ErrMissing) 97 s.CheckCalls(c, nil) 98 } 99 100 func (s *ManifoldSuite) TestStartCannotOpenAPI(c *gc.C) { 101 s.SetErrors(errors.New("no api for you")) 102 103 worker, err := s.manifold.Start(s.getResource) 104 c.Check(worker, gc.IsNil) 105 c.Check(err, gc.ErrorMatches, "cannot open api: no api for you") 106 s.CheckCalls(c, []testing.StubCall{{ 107 FuncName: "openConnection", 108 Args: []interface{}{s.agent}, 109 }}) 110 } 111 112 func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdSet(c *gc.C) { 113 worker, err := s.manifold.Start(s.getResource) 114 c.Check(err, jc.ErrorIsNil) 115 defer assertStop(c, worker) 116 s.CheckCalls(c, []testing.StubCall{{ 117 FuncName: "openConnection", 118 Args: []interface{}{s.agent}, 119 }, { 120 FuncName: "Unlock", 121 }}) 122 } 123 124 func (s *ManifoldSuite) setupMutatorTest(c *gc.C) agent.ConfigMutator { 125 s.agent.env = names.EnvironTag{} 126 s.conn.stub = &s.Stub // will be unsafe if worker stopped before test finished 127 s.SetErrors( 128 nil, // openConnection, 129 errors.New("nonfatal: always logged and ignored"), // ChangeConfig 130 ) 131 132 worker, err := s.manifold.Start(s.getResource) 133 c.Assert(err, jc.ErrorIsNil) 134 s.AddCleanup(func(c *gc.C) { assertStop(c, worker) }) 135 136 s.CheckCallNames(c, "openConnection", "ChangeConfig", "Unlock") 137 changeArgs := s.Calls()[1].Args 138 c.Assert(changeArgs, gc.HasLen, 1) 139 s.ResetCalls() 140 return changeArgs[0].(agent.ConfigMutator) 141 } 142 143 func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdNotSet(c *gc.C) { 144 mutator := s.setupMutatorTest(c) 145 mockSetter := &mockSetter{stub: &s.Stub} 146 147 err := mutator(mockSetter) 148 c.Check(err, jc.ErrorIsNil) 149 s.CheckCalls(c, []testing.StubCall{{ 150 FuncName: "EnvironTag", 151 }, { 152 FuncName: "Migrate", 153 Args: []interface{}{agent.MigrateParams{ 154 Environment: coretesting.EnvironmentTag, 155 }}, 156 }}) 157 } 158 159 func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdNotSetBadAPIState(c *gc.C) { 160 mutator := s.setupMutatorTest(c) 161 s.SetErrors(errors.New("no tag for you")) 162 163 err := mutator(nil) 164 c.Check(err, gc.ErrorMatches, "no environment uuid set on api: no tag for you") 165 s.CheckCalls(c, []testing.StubCall{{ 166 FuncName: "EnvironTag", 167 }}) 168 } 169 170 func (s *ManifoldSuite) TestStartSuccessWithEnvironnmentIdNotSetMigrateFailure(c *gc.C) { 171 mutator := s.setupMutatorTest(c) 172 mockSetter := &mockSetter{stub: &s.Stub} 173 s.SetErrors(nil, errors.New("migrate failure")) 174 175 err := mutator(mockSetter) 176 c.Check(err, gc.ErrorMatches, "migrate failure") 177 s.CheckCalls(c, []testing.StubCall{{ 178 FuncName: "EnvironTag", 179 }, { 180 FuncName: "Migrate", 181 Args: []interface{}{agent.MigrateParams{ 182 Environment: coretesting.EnvironmentTag, 183 }}, 184 }}) 185 } 186 187 func (s *ManifoldSuite) setupWorkerTest(c *gc.C) worker.Worker { 188 w, err := s.manifold.Start(s.getResource) 189 c.Assert(err, jc.ErrorIsNil) 190 s.AddCleanup(func(c *gc.C) { w.Kill() }) 191 return w 192 } 193 194 func (s *ManifoldSuite) TestKillWorkerClosesConnection(c *gc.C) { 195 worker := s.setupWorkerTest(c) 196 assertStop(c, worker) 197 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 198 FuncName: "Close", 199 }}) 200 } 201 202 func (s *ManifoldSuite) TestKillWorkerReportsCloseErr(c *gc.C) { 203 s.conn.stub.SetErrors(errors.New("bad plumbing")) 204 worker := s.setupWorkerTest(c) 205 206 assertStopError(c, worker, "bad plumbing") 207 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 208 FuncName: "Close", 209 }}) 210 } 211 212 func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithCloseErr(c *gc.C) { 213 s.conn.stub.SetErrors(errors.New("bad plumbing")) 214 worker := s.setupWorkerTest(c) 215 216 close(s.conn.broken) 217 err := worker.Wait() 218 c.Check(err, gc.ErrorMatches, "bad plumbing") 219 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 220 FuncName: "Close", 221 }}) 222 } 223 224 func (s *ManifoldSuite) TestBrokenConnectionKillsWorkerWithFallbackErr(c *gc.C) { 225 worker := s.setupWorkerTest(c) 226 227 close(s.conn.broken) 228 err := worker.Wait() 229 c.Check(err, gc.ErrorMatches, "api connection broken unexpectedly") 230 s.conn.stub.CheckCalls(c, []testing.StubCall{{ 231 FuncName: "Close", 232 }}) 233 } 234 235 func (s *ManifoldSuite) TestOutputSuccess(c *gc.C) { 236 worker := s.setupWorkerTest(c) 237 238 var apicaller base.APICaller 239 err := s.manifold.Output(worker, &apicaller) 240 c.Check(err, jc.ErrorIsNil) 241 c.Check(apicaller, gc.Equals, s.conn) 242 } 243 244 func (s *ManifoldSuite) TestOutputBadWorker(c *gc.C) { 245 var apicaller base.APICaller 246 err := s.manifold.Output(dummyWorker{}, &apicaller) 247 c.Check(apicaller, gc.IsNil) 248 c.Check(err.Error(), gc.Equals, "expected *apicaller.apiConnWorker->*base.APICaller; got apicaller_test.dummyWorker->*base.APICaller") 249 } 250 251 func (s *ManifoldSuite) TestOutputBadTarget(c *gc.C) { 252 worker := s.setupWorkerTest(c) 253 254 var apicaller interface{} 255 err := s.manifold.Output(worker, &apicaller) 256 c.Check(apicaller, gc.IsNil) 257 c.Check(err.Error(), gc.Equals, "expected *apicaller.apiConnWorker->*base.APICaller; got *apicaller.apiConnWorker->*interface {}") 258 }