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

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package peergrouper_test
     5  
     6  import (
     7  	"time"
     8  
     9  	"github.com/juju/clock/testclock"
    10  	"github.com/juju/errors"
    11  	"github.com/juju/names/v5"
    12  	"github.com/juju/testing"
    13  	jc "github.com/juju/testing/checkers"
    14  	"github.com/juju/worker/v3"
    15  	"github.com/juju/worker/v3/dependency"
    16  	dt "github.com/juju/worker/v3/dependency/testing"
    17  	"github.com/juju/worker/v3/workertest"
    18  	"github.com/prometheus/client_golang/prometheus"
    19  	gc "gopkg.in/check.v1"
    20  
    21  	"github.com/juju/juju/agent"
    22  	"github.com/juju/juju/controller"
    23  	"github.com/juju/juju/state"
    24  	statetesting "github.com/juju/juju/state/testing"
    25  	"github.com/juju/juju/worker/peergrouper"
    26  )
    27  
    28  type ManifoldSuite struct {
    29  	statetesting.StateSuite
    30  
    31  	manifold     dependency.Manifold
    32  	context      dependency.Context
    33  	clock        *testclock.Clock
    34  	agent        *mockAgent
    35  	hub          *mockHub
    36  	registerer   *fakeRegisterer
    37  	stateTracker stubStateTracker
    38  
    39  	stub testing.Stub
    40  }
    41  
    42  var _ = gc.Suite(&ManifoldSuite{})
    43  
    44  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    45  	s.StateSuite.SetUpTest(c)
    46  
    47  	s.clock = testclock.NewClock(time.Time{})
    48  	s.agent = &mockAgent{conf: mockAgentConfig{
    49  		info: &controller.StateServingInfo{
    50  			StatePort: 1234,
    51  			APIPort:   5678,
    52  		},
    53  	}}
    54  	s.hub = &mockHub{}
    55  	s.registerer = &fakeRegisterer{}
    56  	s.stateTracker = stubStateTracker{pool: s.StatePool}
    57  	s.stub.ResetCalls()
    58  
    59  	s.context = s.newContext(nil)
    60  	s.manifold = peergrouper.Manifold(peergrouper.ManifoldConfig{
    61  		AgentName:            "agent",
    62  		ClockName:            "clock",
    63  		ControllerPortName:   "controller-port",
    64  		StateName:            "state",
    65  		Hub:                  s.hub,
    66  		NewWorker:            s.newWorker,
    67  		PrometheusRegisterer: s.registerer,
    68  	})
    69  }
    70  
    71  func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context {
    72  	resources := map[string]interface{}{
    73  		"agent":           s.agent,
    74  		"clock":           s.clock,
    75  		"controller-port": nil,
    76  		"state":           &s.stateTracker,
    77  	}
    78  	for k, v := range overlay {
    79  		resources[k] = v
    80  	}
    81  	return dt.StubContext(nil, resources)
    82  }
    83  
    84  func (s *ManifoldSuite) newWorker(config peergrouper.Config) (worker.Worker, error) {
    85  	s.stub.MethodCall(s, "NewWorker", config)
    86  	if err := s.stub.NextErr(); err != nil {
    87  		return nil, err
    88  	}
    89  	w := worker.NewRunner(worker.RunnerParams{})
    90  	s.AddCleanup(func(c *gc.C) { workertest.CleanKill(c, w) })
    91  	return w, nil
    92  }
    93  
    94  var expectedInputs = []string{"agent", "clock", "controller-port", "state"}
    95  
    96  func (s *ManifoldSuite) TestInputs(c *gc.C) {
    97  	c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs)
    98  }
    99  
   100  func (s *ManifoldSuite) TestMissingInputs(c *gc.C) {
   101  	for _, input := range expectedInputs {
   102  		context := s.newContext(map[string]interface{}{
   103  			input: dependency.ErrMissing,
   104  		})
   105  		_, err := s.manifold.Start(context)
   106  		c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing)
   107  	}
   108  }
   109  
   110  func (s *ManifoldSuite) TestStart(c *gc.C) {
   111  	w := s.startWorkerClean(c)
   112  	workertest.CleanKill(c, w)
   113  
   114  	s.stub.CheckCallNames(c, "NewWorker")
   115  	args := s.stub.Calls()[0].Args
   116  	c.Assert(args, gc.HasLen, 1)
   117  	c.Assert(args[0], gc.FitsTypeOf, peergrouper.Config{})
   118  	config := args[0].(peergrouper.Config)
   119  
   120  	c.Assert(config.ControllerId(), gc.Equals, "10")
   121  	config.ControllerId = nil
   122  	c.Assert(config, jc.DeepEquals, peergrouper.Config{
   123  		State:        peergrouper.StateShim{State: s.State},
   124  		MongoSession: peergrouper.MongoSessionShim{Session: s.State.MongoSession()},
   125  		APIHostPortsSetter: &peergrouper.CachingAPIHostPortsSetter{
   126  			APIHostPortsSetter: s.State,
   127  		},
   128  		Clock:                s.clock,
   129  		Hub:                  s.hub,
   130  		MongoPort:            1234,
   131  		APIPort:              5678,
   132  		SupportsHA:           true,
   133  		PrometheusRegisterer: s.registerer,
   134  	})
   135  }
   136  
   137  func (s *ManifoldSuite) TestStopWorkerClosesState(c *gc.C) {
   138  	w := s.startWorkerClean(c)
   139  	defer workertest.CleanKill(c, w)
   140  
   141  	s.stateTracker.CheckCallNames(c, "Use")
   142  
   143  	workertest.CleanKill(c, w)
   144  	s.stateTracker.CheckCallNames(c, "Use", "Done")
   145  }
   146  
   147  func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker {
   148  	w, err := s.manifold.Start(s.context)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	workertest.CheckAlive(c, w)
   151  	return w
   152  }
   153  
   154  func (s *ManifoldSuite) TestNoStateServingInfoClosesState(c *gc.C) {
   155  	s.agent.conf.info = nil
   156  
   157  	_, err := s.manifold.Start(s.context)
   158  	c.Assert(err, gc.ErrorMatches, "state serving info missing from agent config")
   159  
   160  	s.stateTracker.CheckCallNames(c, "Use", "Done")
   161  }
   162  
   163  type stubStateTracker struct {
   164  	testing.Stub
   165  	pool *state.StatePool
   166  }
   167  
   168  func (s *stubStateTracker) Use() (*state.StatePool, error) {
   169  	s.MethodCall(s, "Use")
   170  	return s.pool, s.NextErr()
   171  }
   172  
   173  func (s *stubStateTracker) Done() error {
   174  	s.MethodCall(s, "Done")
   175  	return s.NextErr()
   176  }
   177  
   178  func (s *stubStateTracker) Report() map[string]interface{} {
   179  	s.MethodCall(s, "Report")
   180  	return nil
   181  }
   182  
   183  type mockAgent struct {
   184  	agent.Agent
   185  	conf mockAgentConfig
   186  }
   187  
   188  func (ma *mockAgent) CurrentConfig() agent.Config {
   189  	return &ma.conf
   190  }
   191  
   192  type mockAgentConfig struct {
   193  	agent.Config
   194  	info *controller.StateServingInfo
   195  }
   196  
   197  func (c *mockAgentConfig) Tag() names.Tag {
   198  	return names.NewMachineTag("10")
   199  }
   200  
   201  func (c *mockAgentConfig) StateServingInfo() (controller.StateServingInfo, bool) {
   202  	if c.info != nil {
   203  		return *c.info, true
   204  	}
   205  	return controller.StateServingInfo{}, false
   206  }
   207  
   208  type mockHub struct {
   209  	peergrouper.Hub
   210  }
   211  
   212  type fakeRegisterer struct {
   213  	prometheus.Registerer
   214  }