github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/worker/httpserver/manifold_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package httpserver_test
     5  
     6  import (
     7  	"crypto/tls"
     8  	"time"
     9  
    10  	"github.com/juju/clock/testclock"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	mgotesting "github.com/juju/mgo/v3/testing"
    14  	"github.com/juju/pubsub/v2"
    15  	"github.com/juju/testing"
    16  	jc "github.com/juju/testing/checkers"
    17  	"github.com/juju/worker/v3"
    18  	"github.com/juju/worker/v3/dependency"
    19  	dt "github.com/juju/worker/v3/dependency/testing"
    20  	"github.com/juju/worker/v3/workertest"
    21  	gc "gopkg.in/check.v1"
    22  
    23  	"github.com/juju/juju/apiserver/apiserverhttp"
    24  	"github.com/juju/juju/controller"
    25  	"github.com/juju/juju/pki"
    26  	pkitest "github.com/juju/juju/pki/test"
    27  	"github.com/juju/juju/state"
    28  	statetesting "github.com/juju/juju/state/testing"
    29  	"github.com/juju/juju/worker/httpserver"
    30  )
    31  
    32  type ManifoldSuite struct {
    33  	testing.IsolationSuite
    34  	statetesting.StateSuite
    35  
    36  	authority            pki.Authority
    37  	config               httpserver.ManifoldConfig
    38  	manifold             dependency.Manifold
    39  	context              dependency.Context
    40  	state                stubStateTracker
    41  	hub                  *pubsub.StructuredHub
    42  	mux                  *apiserverhttp.Mux
    43  	clock                *testclock.Clock
    44  	prometheusRegisterer stubPrometheusRegisterer
    45  	tlsConfig            *tls.Config
    46  	controllerConfig     controller.Config
    47  
    48  	stub testing.Stub
    49  }
    50  
    51  var _ = gc.Suite(&ManifoldSuite{})
    52  
    53  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    54  	s.IsolationSuite.SetUpTest(c)
    55  
    56  	authority, err := pkitest.NewTestAuthority()
    57  	c.Assert(err, jc.ErrorIsNil)
    58  	s.authority = authority
    59  
    60  	s.mux = &apiserverhttp.Mux{}
    61  	s.hub = pubsub.NewStructuredHub(nil)
    62  	s.clock = testclock.NewClock(time.Now())
    63  	s.prometheusRegisterer = stubPrometheusRegisterer{}
    64  	s.tlsConfig = &tls.Config{}
    65  	s.controllerConfig = controller.Config(map[string]interface{}{
    66  		"api-port":            1024,
    67  		"controller-api-port": 2048,
    68  		"api-port-open-delay": "5s",
    69  	})
    70  	s.stub.ResetCalls()
    71  
    72  	s.context = s.newContext(nil)
    73  	s.config = httpserver.ManifoldConfig{
    74  		AgentName:            "machine-42",
    75  		AuthorityName:        "authority",
    76  		HubName:              "hub",
    77  		StateName:            "state",
    78  		MuxName:              "mux",
    79  		APIServerName:        "api-server",
    80  		Clock:                s.clock,
    81  		PrometheusRegisterer: &s.prometheusRegisterer,
    82  		MuxShutdownWait:      1 * time.Minute,
    83  		LogDir:               "log-dir",
    84  		GetControllerConfig:  s.getControllerConfig,
    85  		NewTLSConfig:         s.newTLSConfig,
    86  		NewWorker:            s.newWorker,
    87  		Logger:               loggo.GetLogger("test"),
    88  	}
    89  	s.manifold = httpserver.Manifold(s.config)
    90  	s.StateSuite.SetUpTest(c)
    91  	s.state = stubStateTracker{
    92  		pool: s.StatePool,
    93  	}
    94  }
    95  
    96  func (s *ManifoldSuite) SetUpSuite(c *gc.C) {
    97  	s.IsolationSuite.SetUpSuite(c)
    98  
    99  	mgotesting.MgoServer.EnableReplicaSet = true
   100  	err := mgotesting.MgoServer.Start(nil)
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	s.IsolationSuite.AddCleanup(func(*gc.C) { mgotesting.MgoServer.Destroy() })
   103  
   104  	s.StateSuite.SetUpSuite(c)
   105  }
   106  
   107  func (s *ManifoldSuite) TearDownSuite(c *gc.C) {
   108  	s.StateSuite.TearDownSuite(c)
   109  	s.IsolationSuite.TearDownSuite(c)
   110  }
   111  
   112  func (s *ManifoldSuite) TearDownTest(c *gc.C) {
   113  	s.StateSuite.TearDownTest(c)
   114  	s.IsolationSuite.TearDownTest(c)
   115  }
   116  
   117  func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context {
   118  	resources := map[string]interface{}{
   119  		"authority":      s.authority,
   120  		"state":          &s.state,
   121  		"hub":            s.hub,
   122  		"mux":            s.mux,
   123  		"raft-transport": nil,
   124  		"api-server":     nil,
   125  	}
   126  	for k, v := range overlay {
   127  		resources[k] = v
   128  	}
   129  	return dt.StubContext(nil, resources)
   130  }
   131  
   132  func (s *ManifoldSuite) getControllerConfig(st *state.State) (controller.Config, error) {
   133  	s.stub.MethodCall(s, "GetControllerConfig", st)
   134  	if err := s.stub.NextErr(); err != nil {
   135  		return nil, err
   136  	}
   137  	return s.controllerConfig, nil
   138  }
   139  
   140  func (s *ManifoldSuite) newTLSConfig(
   141  	st *state.State,
   142  	_ httpserver.SNIGetterFunc,
   143  	_ httpserver.Logger,
   144  ) (*tls.Config, error) {
   145  	s.stub.MethodCall(s, "NewTLSConfig", st)
   146  	if err := s.stub.NextErr(); err != nil {
   147  		return nil, err
   148  	}
   149  	return s.tlsConfig, nil
   150  }
   151  
   152  func (s *ManifoldSuite) newWorker(config httpserver.Config) (worker.Worker, error) {
   153  	s.stub.MethodCall(s, "NewWorker", config)
   154  	if err := s.stub.NextErr(); err != nil {
   155  		return nil, err
   156  	}
   157  	return worker.NewRunner(worker.RunnerParams{}), nil
   158  }
   159  
   160  var expectedInputs = []string{
   161  	"authority",
   162  	"state",
   163  	"mux",
   164  	"hub",
   165  	"api-server",
   166  }
   167  
   168  func (s *ManifoldSuite) TestInputs(c *gc.C) {
   169  	c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs)
   170  }
   171  
   172  func (s *ManifoldSuite) TestMissingInputs(c *gc.C) {
   173  	for _, input := range expectedInputs {
   174  		context := s.newContext(map[string]interface{}{
   175  			input: dependency.ErrMissing,
   176  		})
   177  		_, err := s.manifold.Start(context)
   178  		c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing)
   179  	}
   180  }
   181  
   182  func (s *ManifoldSuite) TestStart(c *gc.C) {
   183  	w := s.startWorkerClean(c)
   184  	workertest.CleanKill(c, w)
   185  
   186  	s.stub.CheckCallNames(c, "NewTLSConfig", "GetControllerConfig", "NewWorker")
   187  	newWorkerArgs := s.stub.Calls()[2].Args
   188  	c.Assert(newWorkerArgs, gc.HasLen, 1)
   189  	c.Assert(newWorkerArgs[0], gc.FitsTypeOf, httpserver.Config{})
   190  	config := newWorkerArgs[0].(httpserver.Config)
   191  
   192  	c.Assert(config, jc.DeepEquals, httpserver.Config{
   193  		AgentName:            "machine-42",
   194  		Clock:                s.clock,
   195  		PrometheusRegisterer: &s.prometheusRegisterer,
   196  		Hub:                  s.hub,
   197  		TLSConfig:            s.tlsConfig,
   198  		Mux:                  s.mux,
   199  		APIPort:              1024,
   200  		APIPortOpenDelay:     5 * time.Second,
   201  		ControllerAPIPort:    2048,
   202  		MuxShutdownWait:      1 * time.Minute,
   203  		LogDir:               "log-dir",
   204  		Logger:               s.config.Logger,
   205  	})
   206  }
   207  
   208  func (s *ManifoldSuite) TestValidate(c *gc.C) {
   209  	type test struct {
   210  		f      func(*httpserver.ManifoldConfig)
   211  		expect string
   212  	}
   213  	tests := []test{{
   214  		func(cfg *httpserver.ManifoldConfig) { cfg.AgentName = "" },
   215  		"empty AgentName not valid",
   216  	}, {
   217  		func(cfg *httpserver.ManifoldConfig) { cfg.AuthorityName = "" },
   218  		"empty AuthorityName not valid",
   219  	}, {
   220  		func(cfg *httpserver.ManifoldConfig) { cfg.StateName = "" },
   221  		"empty StateName not valid",
   222  	}, {
   223  		func(cfg *httpserver.ManifoldConfig) { cfg.MuxName = "" },
   224  		"empty MuxName not valid",
   225  	}, {
   226  		func(cfg *httpserver.ManifoldConfig) { cfg.MuxShutdownWait = 0 },
   227  		"MuxShutdownWait 0s not valid",
   228  	}, {
   229  		func(cfg *httpserver.ManifoldConfig) { cfg.LogDir = "" },
   230  		"empty LogDir not valid",
   231  	}, {
   232  		func(cfg *httpserver.ManifoldConfig) { cfg.APIServerName = "" },
   233  		"empty APIServerName not valid",
   234  	}, {
   235  		func(cfg *httpserver.ManifoldConfig) { cfg.PrometheusRegisterer = nil },
   236  		"nil PrometheusRegisterer not valid",
   237  	}, {
   238  		func(cfg *httpserver.ManifoldConfig) { cfg.GetControllerConfig = nil },
   239  		"nil GetControllerConfig not valid",
   240  	}, {
   241  		func(cfg *httpserver.ManifoldConfig) { cfg.NewTLSConfig = nil },
   242  		"nil NewTLSConfig not valid",
   243  	}, {
   244  		func(cfg *httpserver.ManifoldConfig) { cfg.NewWorker = nil },
   245  		"nil NewWorker not valid",
   246  	}}
   247  	for i, test := range tests {
   248  		c.Logf("test #%d (%s)", i, test.expect)
   249  		config := s.config
   250  		test.f(&config)
   251  		manifold := httpserver.Manifold(config)
   252  		w, err := manifold.Start(s.context)
   253  		workertest.CheckNilOrKill(c, w)
   254  		c.Check(err, gc.ErrorMatches, test.expect)
   255  	}
   256  }
   257  
   258  func (s *ManifoldSuite) TestStopWorkerClosesState(c *gc.C) {
   259  	w := s.startWorkerClean(c)
   260  	defer workertest.CleanKill(c, w)
   261  
   262  	s.state.CheckCallNames(c, "Use")
   263  
   264  	workertest.CleanKill(c, w)
   265  	s.state.CheckCallNames(c, "Use", "Done")
   266  }
   267  
   268  func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker {
   269  	w, err := s.manifold.Start(s.context)
   270  	c.Assert(err, jc.ErrorIsNil)
   271  	workertest.CheckAlive(c, w)
   272  	return w
   273  }