github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/worker/caasoperator/manifold_test.go (about)

     1  // Copyright 2017 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package caasoperator_test
     5  
     6  import (
     7  	"os"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/juju/clock/testclock"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/loggo"
    14  	"github.com/juju/names/v5"
    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  	"go.uber.org/mock/gomock"
    22  	gc "gopkg.in/check.v1"
    23  
    24  	"github.com/juju/juju/api/agent/secretsmanager"
    25  	"github.com/juju/juju/api/base"
    26  	"github.com/juju/juju/caas"
    27  	"github.com/juju/juju/caas/kubernetes/provider/exec"
    28  	"github.com/juju/juju/core/machinelock"
    29  	"github.com/juju/juju/rpc/params"
    30  	_ "github.com/juju/juju/secrets/provider/all"
    31  	coretesting "github.com/juju/juju/testing"
    32  	"github.com/juju/juju/worker/caasoperator"
    33  	"github.com/juju/juju/worker/caasoperator/mocks"
    34  	"github.com/juju/juju/worker/uniter"
    35  )
    36  
    37  type ManifoldSuite struct {
    38  	testing.IsolationSuite
    39  
    40  	manifold        dependency.Manifold
    41  	agent           fakeAgent
    42  	apiCaller       *mocks.MockAPICaller
    43  	charmDownloader fakeDownloader
    44  	client          fakeClient
    45  	clock           *testclock.Clock
    46  	dataDir         string
    47  	stub            testing.Stub
    48  }
    49  
    50  var _ = gc.Suite(&ManifoldSuite{})
    51  
    52  func (s *ManifoldSuite) SetUpTest(c *gc.C) {
    53  	s.IsolationSuite.SetUpTest(c)
    54  
    55  	os.Setenv("JUJU_OPERATOR_SERVICE_IP", "127.0.0.1")
    56  	os.Setenv("JUJU_OPERATOR_POD_IP", "127.0.0.2")
    57  
    58  	s.dataDir = c.MkDir()
    59  	s.agent = fakeAgent{
    60  		config: fakeAgentConfig{
    61  			tag:     names.NewApplicationTag("gitlab"),
    62  			dataDir: s.dataDir,
    63  		},
    64  	}
    65  	s.clock = testclock.NewClock(time.Time{})
    66  	s.stub.ResetCalls()
    67  }
    68  
    69  func (s *ManifoldSuite) TearDownTest(c *gc.C) {
    70  	os.Setenv("JUJU_OPERATOR_SERVICE_IP", "")
    71  	os.Setenv("JUJU_OPERATOR_POD_IP", "")
    72  
    73  	s.IsolationSuite.TearDownTest(c)
    74  }
    75  
    76  func (s *ManifoldSuite) setupManifold(c *gc.C) *gomock.Controller {
    77  	ctrl := gomock.NewController(c)
    78  	s.apiCaller = mocks.NewMockAPICaller(ctrl)
    79  
    80  	s.manifold = caasoperator.Manifold(caasoperator.ManifoldConfig{
    81  		AgentName:             "agent",
    82  		APICallerName:         "api-caller",
    83  		ClockName:             "clock",
    84  		CharmDirName:          "charm-dir",
    85  		HookRetryStrategyName: "hook-retry-strategy",
    86  		ProfileDir:            "profile-dir",
    87  		MachineLock:           &fakemachinelock{},
    88  		NewWorker:             s.newWorker,
    89  		NewClient:             s.newClient,
    90  		NewCharmDownloader:    s.newCharmDownloader,
    91  		LeadershipGuarantee:   30 * time.Second,
    92  		NewExecClient: func(modelName string) (exec.Executor, error) {
    93  			return mocks.NewMockExecutor(ctrl), nil
    94  		},
    95  		LoadOperatorInfo: func(paths caasoperator.Paths) (*caas.OperatorInfo, error) {
    96  			return &caas.OperatorInfo{
    97  				CACert:     coretesting.CACert,
    98  				Cert:       coretesting.ServerCert,
    99  				PrivateKey: coretesting.ServerKey,
   100  			}, nil
   101  		},
   102  		Logger: loggo.GetLogger("test"),
   103  	})
   104  	return ctrl
   105  }
   106  
   107  func (s *ManifoldSuite) newContext(overlay map[string]interface{}) dependency.Context {
   108  	resources := map[string]interface{}{
   109  		"agent":               &s.agent,
   110  		"api-caller":          s.apiCaller,
   111  		"clock":               s.clock,
   112  		"charm-dir":           &mockCharmDirGuard{},
   113  		"hook-retry-strategy": params.RetryStrategy{},
   114  	}
   115  	for k, v := range overlay {
   116  		resources[k] = v
   117  	}
   118  	return dt.StubContext(nil, resources)
   119  }
   120  
   121  func (s *ManifoldSuite) newWorker(config caasoperator.Config) (worker.Worker, error) {
   122  	s.stub.MethodCall(s, "NewWorker", config)
   123  	if err := s.stub.NextErr(); err != nil {
   124  		return nil, err
   125  	}
   126  	w := worker.NewRunner(worker.RunnerParams{})
   127  	s.AddCleanup(func(c *gc.C) { workertest.DirtyKill(c, w) })
   128  	return w, nil
   129  }
   130  
   131  func (s *ManifoldSuite) newClient(caller base.APICaller) caasoperator.Client {
   132  	s.stub.MethodCall(s, "NewClient", caller)
   133  	return &s.client
   134  }
   135  
   136  func (s *ManifoldSuite) newCharmDownloader(caller base.APICaller) caasoperator.Downloader {
   137  	s.stub.MethodCall(s, "NewCharmDownloader", caller)
   138  	return &s.charmDownloader
   139  }
   140  
   141  var expectedInputs = []string{"agent", "api-caller", "clock", "charm-dir", "hook-retry-strategy"}
   142  
   143  func (s *ManifoldSuite) TestInputs(c *gc.C) {
   144  	ctrl := s.setupManifold(c)
   145  	defer ctrl.Finish()
   146  
   147  	c.Assert(s.manifold.Inputs, jc.SameContents, expectedInputs)
   148  }
   149  
   150  func (s *ManifoldSuite) TestMissingInputs(c *gc.C) {
   151  	ctrl := s.setupManifold(c)
   152  	defer ctrl.Finish()
   153  
   154  	for _, input := range expectedInputs {
   155  		context := s.newContext(map[string]interface{}{
   156  			input: dependency.ErrMissing,
   157  		})
   158  		_, err := s.manifold.Start(context)
   159  		c.Assert(errors.Cause(err), gc.Equals, dependency.ErrMissing)
   160  	}
   161  }
   162  
   163  func (s *ManifoldSuite) TestStart(c *gc.C) {
   164  	w := s.startWorkerClean(c)
   165  	workertest.CleanKill(c, w)
   166  
   167  	s.stub.CheckCallNames(c, "NewClient", "NewCharmDownloader", "NewWorker")
   168  	s.stub.CheckCall(c, 0, "NewClient", s.apiCaller)
   169  	s.stub.CheckCall(c, 1, "NewCharmDownloader", s.apiCaller)
   170  
   171  	args := s.stub.Calls()[2].Args
   172  	c.Assert(args, gc.HasLen, 1)
   173  	c.Assert(args[0], gc.FitsTypeOf, caasoperator.Config{})
   174  	config := args[0].(caasoperator.Config)
   175  
   176  	// Don't care about some helper funcs.
   177  	c.Assert(config.UniterParams, gc.NotNil)
   178  	c.Assert(config.LeadershipTrackerFunc, gc.NotNil)
   179  	c.Assert(config.UniterFacadeFunc, gc.NotNil)
   180  	c.Assert(config.StartUniterFunc, gc.NotNil)
   181  	c.Assert(config.RunListenerSocketFunc, gc.NotNil)
   182  	c.Assert(config.UniterParams.UpdateStatusSignal, gc.NotNil)
   183  	c.Assert(config.UniterParams.NewOperationExecutor, gc.NotNil)
   184  	c.Assert(config.UniterParams.NewProcessRunner, gc.NotNil)
   185  	c.Assert(config.UniterParams.NewDeployer, gc.NotNil)
   186  	c.Assert(config.UniterParams.SecretRotateWatcherFunc, gc.NotNil)
   187  	c.Assert(config.UniterParams.SecretsBackendGetter, gc.NotNil)
   188  	c.Assert(config.Logger, gc.NotNil)
   189  	c.Assert(config.ExecClientGetter, gc.NotNil)
   190  	config.LeadershipTrackerFunc = nil
   191  	config.StartUniterFunc = nil
   192  	config.UniterFacadeFunc = nil
   193  	config.ResourcesFacadeFunc = nil
   194  	config.PayloadFacadeFunc = nil
   195  	config.RunListenerSocketFunc = nil
   196  	config.UniterParams.UpdateStatusSignal = nil
   197  	config.UniterParams.NewOperationExecutor = nil
   198  	config.UniterParams.NewDeployer = nil
   199  	config.UniterParams.NewProcessRunner = nil
   200  	config.UniterParams.SecretRotateWatcherFunc = nil
   201  	config.UniterParams.SecretExpiryWatcherFunc = nil
   202  	config.UniterParams.SecretsBackendGetter = nil
   203  	config.Logger = nil
   204  	config.ExecClientGetter = nil
   205  
   206  	c.Assert(config.UniterParams.SocketConfig.TLSConfig, gc.NotNil)
   207  	config.UniterParams.SocketConfig.TLSConfig = nil
   208  
   209  	jujuSecretsAPI := secretsmanager.NewClient(s.apiCaller)
   210  	c.Assert(config, jc.DeepEquals, caasoperator.Config{
   211  		ModelUUID:             coretesting.ModelTag.Id(),
   212  		ModelName:             "gitlab-model",
   213  		Application:           "gitlab",
   214  		ProfileDir:            "profile-dir",
   215  		DataDir:               s.dataDir,
   216  		CharmGetter:           &s.client,
   217  		Clock:                 s.clock,
   218  		Downloader:            &s.charmDownloader,
   219  		StatusSetter:          &s.client,
   220  		UnitGetter:            &s.client,
   221  		UnitRemover:           &s.client,
   222  		ContainerStartWatcher: &s.client,
   223  		ApplicationWatcher:    &s.client,
   224  		VersionSetter:         &s.client,
   225  		UniterParams: &uniter.UniterParams{
   226  			DataDir:       s.dataDir,
   227  			MachineLock:   &fakemachinelock{},
   228  			SecretsClient: jujuSecretsAPI,
   229  			CharmDirGuard: &mockCharmDirGuard{},
   230  			Clock:         s.clock,
   231  			SocketConfig: &uniter.SocketConfig{
   232  				ServiceAddress:  "127.0.0.1",
   233  				OperatorAddress: "127.0.0.2",
   234  			},
   235  			Logger: loggo.GetLogger("test.uniter"),
   236  		},
   237  		OperatorInfo: caas.OperatorInfo{
   238  			CACert:     coretesting.CACert,
   239  			Cert:       coretesting.ServerCert,
   240  			PrivateKey: coretesting.ServerKey,
   241  		},
   242  	})
   243  }
   244  
   245  func (s *ManifoldSuite) startWorkerClean(c *gc.C) worker.Worker {
   246  	ctrl := s.setupManifold(c)
   247  	defer ctrl.Finish()
   248  
   249  	s.apiCaller.EXPECT().BestFacadeVersion("SecretsManager").AnyTimes().Return(1)
   250  
   251  	w, err := s.manifold.Start(s.newContext(nil))
   252  	c.Assert(err, jc.ErrorIsNil)
   253  	workertest.CheckAlive(c, w)
   254  	return w
   255  }
   256  
   257  type fakemachinelock struct {
   258  	mu sync.Mutex
   259  }
   260  
   261  func (f *fakemachinelock) Acquire(spec machinelock.Spec) (func(), error) {
   262  	f.mu.Lock()
   263  	return func() {
   264  		f.mu.Unlock()
   265  	}, nil
   266  }
   267  func (f *fakemachinelock) Report(opts ...machinelock.ReportOption) (string, error) {
   268  	return "", nil
   269  }