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: &params.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 = &params.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  }