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

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package storageprovisioner_test
     5  
     6  import (
     7  	stdcontext "context"
     8  	"time"
     9  
    10  	"github.com/juju/clock"
    11  	"github.com/juju/errors"
    12  	"github.com/juju/loggo"
    13  	"github.com/juju/names/v5"
    14  	"github.com/juju/retry"
    15  	"github.com/juju/testing"
    16  	jc "github.com/juju/testing/checkers"
    17  	"github.com/juju/worker/v3/workertest"
    18  	gc "gopkg.in/check.v1"
    19  
    20  	"github.com/juju/juju/environs/context"
    21  	"github.com/juju/juju/rpc/params"
    22  	"github.com/juju/juju/storage"
    23  	coretesting "github.com/juju/juju/testing"
    24  	"github.com/juju/juju/worker/storageprovisioner"
    25  )
    26  
    27  type WorkerSuite struct {
    28  	testing.IsolationSuite
    29  
    30  	config              storageprovisioner.Config
    31  	applicationsWatcher *mockApplicationsWatcher
    32  	lifeGetter          *mockLifecycleManager
    33  
    34  	applicationChanges chan []string
    35  }
    36  
    37  var _ = gc.Suite(&WorkerSuite{})
    38  
    39  func (s *WorkerSuite) SetUpTest(c *gc.C) {
    40  	s.IsolationSuite.SetUpTest(c)
    41  
    42  	s.applicationChanges = make(chan []string)
    43  	s.applicationsWatcher = newMockApplicationsWatcher(s.applicationChanges)
    44  	s.lifeGetter = &mockLifecycleManager{}
    45  
    46  	s.config = storageprovisioner.Config{
    47  		Model:                coretesting.ModelTag,
    48  		Scope:                coretesting.ModelTag,
    49  		Applications:         s.applicationsWatcher,
    50  		Volumes:              newMockVolumeAccessor(),
    51  		Filesystems:          newMockFilesystemAccessor(),
    52  		Life:                 s.lifeGetter,
    53  		Status:               &mockStatusSetter{},
    54  		Clock:                &mockClock{},
    55  		Logger:               loggo.GetLogger("test"),
    56  		Registry:             storage.StaticProviderRegistry{},
    57  		CloudCallContextFunc: func(_ stdcontext.Context) context.ProviderCallContext { return context.NewEmptyCloudCallContext() },
    58  	}
    59  }
    60  
    61  func (s *WorkerSuite) TestValidateConfig(c *gc.C) {
    62  	s.testValidateConfig(c, func(config *storageprovisioner.Config) {
    63  		config.Scope = names.NewApplicationTag("mariadb")
    64  		config.Applications = nil
    65  	}, `nil Applications not valid`)
    66  }
    67  
    68  func (s *WorkerSuite) testValidateConfig(c *gc.C, f func(*storageprovisioner.Config), expect string) {
    69  	config := s.config
    70  	f(&config)
    71  	w, err := storageprovisioner.NewCaasWorker(config)
    72  	if err == nil {
    73  		workertest.DirtyKill(c, w)
    74  	}
    75  	c.Check(err, gc.ErrorMatches, expect)
    76  }
    77  
    78  func (s *WorkerSuite) TestStartStop(c *gc.C) {
    79  	w, err := storageprovisioner.NewCaasWorker(s.config)
    80  	c.Assert(err, jc.ErrorIsNil)
    81  	workertest.CheckAlive(c, w)
    82  	workertest.CleanKill(c, w)
    83  }
    84  
    85  func (s *WorkerSuite) TestWatchApplicationDead(c *gc.C) {
    86  	w, err := storageprovisioner.NewCaasWorker(s.config)
    87  	c.Assert(err, jc.ErrorIsNil)
    88  	defer workertest.CleanKill(c, w)
    89  
    90  	select {
    91  	case s.applicationChanges <- []string{"postgresql"}:
    92  	case <-time.After(coretesting.LongWait):
    93  		c.Fatal("timed out sending applications change")
    94  	}
    95  
    96  	// Given the worker time to startup.
    97  	retryCallArgs := retry.CallArgs{
    98  		Clock:       clock.WallClock,
    99  		MaxDuration: coretesting.LongWait,
   100  		Delay:       10 * time.Millisecond,
   101  		Func: func() error {
   102  			if len(s.config.Filesystems.(*mockFilesystemAccessor).Calls()) > 0 {
   103  				return nil
   104  			}
   105  			return errors.NotYetAvailablef("Worker not up")
   106  		},
   107  	}
   108  	err = retry.Call(retryCallArgs)
   109  	c.Assert(err, jc.ErrorIsNil)
   110  
   111  	workertest.CleanKill(c, w)
   112  	// Only call is to watch model.
   113  	s.config.Filesystems.(*mockFilesystemAccessor).CheckCallNames(c, "WatchFilesystems")
   114  	s.config.Filesystems.(*mockFilesystemAccessor).CheckCall(c, 0, "WatchFilesystems", coretesting.ModelTag)
   115  }
   116  
   117  func (s *WorkerSuite) TestStopsWatchingApplicationBecauseApplicationRemoved(c *gc.C) {
   118  	s.assertStopsWatchingApplication(c, func() {
   119  		s.lifeGetter.err = &params.Error{Code: params.CodeNotFound}
   120  	})
   121  }
   122  
   123  func (s *WorkerSuite) assertStopsWatchingApplication(c *gc.C, lifeGetterInjecter func()) {
   124  	w, err := storageprovisioner.NewCaasWorker(s.config)
   125  	c.Assert(err, jc.ErrorIsNil)
   126  	defer workertest.CleanKill(c, w)
   127  
   128  	select {
   129  	case s.applicationChanges <- []string{"mariadb"}:
   130  	case <-time.After(coretesting.LongWait):
   131  		c.Fatal("timed out sending applications change")
   132  	}
   133  
   134  	// Check that the worker is running or not;
   135  	// given it time to startup.
   136  	startingRetryCallArgs := retry.CallArgs{
   137  		Clock:       clock.WallClock,
   138  		MaxDuration: coretesting.LongWait,
   139  		Delay:       10 * time.Millisecond,
   140  		Func: func() error {
   141  			_, running := storageprovisioner.StorageWorker(w, "mariadb")
   142  			if running {
   143  				return nil
   144  			}
   145  			return errors.NotYetAvailablef("Worker not up")
   146  		},
   147  	}
   148  	err = retry.Call(startingRetryCallArgs)
   149  	c.Assert(err, jc.ErrorIsNil)
   150  
   151  	// Add an additional app worker so we can check that the correct one is accessed.
   152  	storageprovisioner.NewStorageWorker(c, w, "postgresql")
   153  
   154  	if lifeGetterInjecter != nil {
   155  		lifeGetterInjecter()
   156  	}
   157  	select {
   158  	case s.applicationChanges <- []string{"postgresql"}:
   159  	case <-time.After(coretesting.LongWait):
   160  		c.Fatal("timed out sending applications change")
   161  	}
   162  
   163  	// The mariadb worker should still be running.
   164  	_, ok := storageprovisioner.StorageWorker(w, "mariadb")
   165  	c.Assert(ok, jc.IsTrue)
   166  
   167  	// Check that the postgresql worker is running or not;
   168  	// given it time to shutdown.
   169  	stoppingRetryCallArgs := retry.CallArgs{
   170  		Clock:       clock.WallClock,
   171  		MaxDuration: coretesting.LongWait,
   172  		Delay:       10 * time.Millisecond,
   173  		Func: func() error {
   174  			_, running := storageprovisioner.StorageWorker(w, "postgresql")
   175  			if !running {
   176  				return nil
   177  			}
   178  			return errors.NotYetAvailablef("Worker not down")
   179  		},
   180  	}
   181  	err = retry.Call(stoppingRetryCallArgs)
   182  	c.Assert(err, jc.ErrorIsNil)
   183  
   184  	workertest.CleanKill(c, w)
   185  	workertest.CheckKilled(c, s.applicationsWatcher.watcher)
   186  }
   187  
   188  func (s *WorkerSuite) TestStopsWatchingApplicationBecauseApplicationDead(c *gc.C) {
   189  	s.assertStopsWatchingApplication(c, nil)
   190  }
   191  
   192  func (s *WorkerSuite) TestWatcherErrorStopsWorker(c *gc.C) {
   193  	w, err := storageprovisioner.NewCaasWorker(s.config)
   194  	c.Assert(err, jc.ErrorIsNil)
   195  	defer workertest.DirtyKill(c, w)
   196  
   197  	select {
   198  	case s.applicationChanges <- []string{"mariadb"}:
   199  	case <-time.After(coretesting.LongWait):
   200  		c.Fatal("timed out sending applications change")
   201  	}
   202  
   203  	s.applicationsWatcher.watcher.KillErr(errors.New("splat"))
   204  	workertest.CheckKilled(c, s.applicationsWatcher.watcher)
   205  	err = workertest.CheckKilled(c, w)
   206  	c.Assert(err, gc.ErrorMatches, "splat")
   207  }