github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/apiservercertwatcher/manifold_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package apiservercertwatcher_test 5 6 import ( 7 "crypto/tls" 8 "sync" 9 "time" 10 11 "github.com/juju/testing" 12 jc "github.com/juju/testing/checkers" 13 "github.com/juju/utils/voyeur" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/worker.v1" 16 "gopkg.in/juju/worker.v1/dependency" 17 dt "gopkg.in/juju/worker.v1/dependency/testing" 18 "gopkg.in/juju/worker.v1/workertest" 19 20 "github.com/juju/juju/agent" 21 "github.com/juju/juju/apiserver/params" 22 coretesting "github.com/juju/juju/testing" 23 "github.com/juju/juju/worker/apiservercertwatcher" 24 ) 25 26 type ManifoldSuite struct { 27 testing.IsolationSuite 28 29 manifold dependency.Manifold 30 context dependency.Context 31 agent *mockAgent 32 agentConfigChanged *voyeur.Value 33 } 34 35 var _ = gc.Suite(&ManifoldSuite{}) 36 37 func (s *ManifoldSuite) SetUpTest(c *gc.C) { 38 s.IsolationSuite.SetUpTest(c) 39 40 s.agent = &mockAgent{ 41 conf: mockConfig{ 42 info: ¶ms.StateServingInfo{ 43 Cert: coretesting.ServerCert, 44 PrivateKey: coretesting.ServerKey, 45 }, 46 }, 47 } 48 s.context = dt.StubContext(nil, map[string]interface{}{ 49 "agent": s.agent, 50 }) 51 s.agentConfigChanged = voyeur.NewValue(0) 52 s.manifold = apiservercertwatcher.Manifold(apiservercertwatcher.ManifoldConfig{ 53 AgentName: "agent", 54 AgentConfigChanged: s.agentConfigChanged, 55 }) 56 } 57 58 func (s *ManifoldSuite) TestInputs(c *gc.C) { 59 c.Assert(s.manifold.Inputs, jc.SameContents, []string{"agent"}) 60 } 61 62 func (s *ManifoldSuite) TestNilAgentConfigChanged(c *gc.C) { 63 manifold := apiservercertwatcher.Manifold(apiservercertwatcher.ManifoldConfig{ 64 AgentName: "agent", 65 }) 66 _, err := manifold.Start(s.context) 67 c.Assert(err, gc.ErrorMatches, "nil AgentConfigChanged .+") 68 } 69 70 func (s *ManifoldSuite) TestNoAgent(c *gc.C) { 71 context := dt.StubContext(nil, map[string]interface{}{ 72 "agent": dependency.ErrMissing, 73 }) 74 _, err := s.manifold.Start(context) 75 c.Assert(err, gc.Equals, dependency.ErrMissing) 76 } 77 78 func (s *ManifoldSuite) TestNoStateServingInfo(c *gc.C) { 79 s.agent.conf.info = nil 80 _, err := s.manifold.Start(s.context) 81 c.Assert(err, gc.ErrorMatches, "parsing initial certificate: no state serving info in agent config") 82 } 83 84 func (s *ManifoldSuite) TestStart(c *gc.C) { 85 w := s.startWorkerClean(c) 86 workertest.CleanKill(c, w) 87 } 88 89 func (s *ManifoldSuite) TestOutput(c *gc.C) { 90 w := s.startWorkerClean(c) 91 defer workertest.CleanKill(c, w) 92 93 var getCert func() *tls.Certificate 94 err := s.manifold.Output(w, &getCert) 95 c.Assert(err, jc.ErrorIsNil) 96 97 cert := getCert() 98 c.Assert(cert, gc.NotNil) 99 c.Assert(cert.Leaf, gc.NotNil) 100 101 cert_ := getCert() 102 c.Assert(cert, gc.Equals, cert_) 103 } 104 105 func (s *ManifoldSuite) TestCertUpdated(c *gc.C) { 106 w := s.startWorkerClean(c) 107 defer workertest.CleanKill(c, w) 108 109 var getCert func() *tls.Certificate 110 err := s.manifold.Output(w, &getCert) 111 c.Assert(err, jc.ErrorIsNil) 112 113 cert := getCert() 114 c.Assert(cert, gc.NotNil) 115 c.Assert(cert.Leaf, gc.NotNil) 116 117 // Update the certificate. 118 s.agent.conf.setCert(coretesting.CACert, coretesting.CAKey) 119 s.agentConfigChanged.Set(0) 120 121 for a := coretesting.LongAttempt.Start(); a.Next(); { 122 cert_ := getCert() 123 if cert_ == cert { 124 continue 125 } 126 return 127 } 128 c.Fatal("timed out waiting for the certificate to change") 129 } 130 131 func (s *ManifoldSuite) TestCertUnchanged(c *gc.C) { 132 w := s.startWorkerClean(c) 133 defer workertest.CleanKill(c, w) 134 135 var getCert func() *tls.Certificate 136 err := s.manifold.Output(w, &getCert) 137 c.Assert(err, jc.ErrorIsNil) 138 139 cert := getCert() 140 c.Assert(cert, gc.NotNil) 141 c.Assert(cert.Leaf, gc.NotNil) 142 143 // Trigger the watcher, but without changing 144 // the cert. The result should be exactly the 145 // same. 146 s.agentConfigChanged.Set(0) 147 time.Sleep(coretesting.ShortWait) 148 149 cert_ := getCert() 150 c.Assert(cert, gc.Equals, cert_) 151 } 152 153 func (s *ManifoldSuite) TestClosedVoyeur(c *gc.C) { 154 w := s.startWorkerClean(c) 155 s.agentConfigChanged.Close() 156 err := workertest.CheckKilled(c, w) 157 c.Assert(err, gc.ErrorMatches, "config changed value closed") 158 } 159 160 func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker { 161 w, err := s.manifold.Start(s.context) 162 c.Assert(err, jc.ErrorIsNil) 163 workertest.CheckAlive(c, w) 164 return w 165 } 166 167 type mockAgent struct { 168 agent.Agent 169 conf mockConfig 170 } 171 172 func (ma *mockAgent) CurrentConfig() agent.Config { 173 return &ma.conf 174 } 175 176 type mockConfig struct { 177 agent.Config 178 179 mu sync.Mutex 180 info *params.StateServingInfo 181 addrs []string 182 } 183 184 func (mc *mockConfig) setCert(cert, key string) { 185 mc.mu.Lock() 186 defer mc.mu.Unlock() 187 if mc.info == nil { 188 mc.info = ¶ms.StateServingInfo{} 189 } 190 mc.info.Cert = cert 191 mc.info.PrivateKey = key 192 } 193 194 func (mc *mockConfig) StateServingInfo() (params.StateServingInfo, bool) { 195 mc.mu.Lock() 196 defer mc.mu.Unlock() 197 if mc.info != nil { 198 return *mc.info, true 199 } 200 return params.StateServingInfo{}, false 201 }