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

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package caasprober_test
     5  
     6  import (
     7  	"errors"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"sync"
    11  
    12  	jc "github.com/juju/testing/checkers"
    13  	gc "gopkg.in/check.v1"
    14  
    15  	k8sconstants "github.com/juju/juju/caas/kubernetes/provider/constants"
    16  	"github.com/juju/juju/observability/probe"
    17  	"github.com/juju/juju/worker/caasprober"
    18  )
    19  
    20  type ControllerSuite struct {
    21  }
    22  
    23  type dummyMux struct {
    24  	AddHandlerFunc    func(string, string, http.Handler) error
    25  	RemoveHandlerFunc func(string, string)
    26  }
    27  
    28  var _ = gc.Suite(&ControllerSuite{})
    29  
    30  func (d *dummyMux) AddHandler(i, j string, h http.Handler) error {
    31  	if d.AddHandlerFunc == nil {
    32  		return nil
    33  	}
    34  	return d.AddHandlerFunc(i, j, h)
    35  }
    36  
    37  func (d *dummyMux) RemoveHandler(i, j string) {
    38  	if d.RemoveHandlerFunc != nil {
    39  		d.RemoveHandlerFunc(i, j)
    40  	}
    41  }
    42  
    43  func (s *ControllerSuite) TestControllerMuxRegistration(c *gc.C) {
    44  	var (
    45  		livenessRegistered    = false
    46  		livenessDeRegistered  = false
    47  		readinessRegistered   = false
    48  		readinessDeRegistered = false
    49  		startupRegistered     = false
    50  		startupDeRegistered   = false
    51  		waitGroup             = sync.WaitGroup{}
    52  	)
    53  
    54  	waitGroup.Add(3)
    55  	mux := dummyMux{
    56  		AddHandlerFunc: func(m, p string, _ http.Handler) error {
    57  			c.Check(m, gc.Equals, http.MethodGet)
    58  			switch p {
    59  			case k8sconstants.AgentHTTPPathLiveness:
    60  				c.Check(livenessRegistered, jc.IsFalse)
    61  				livenessRegistered = true
    62  				waitGroup.Done()
    63  			case k8sconstants.AgentHTTPPathReadiness:
    64  				c.Check(readinessRegistered, jc.IsFalse)
    65  				readinessRegistered = true
    66  				waitGroup.Done()
    67  			case k8sconstants.AgentHTTPPathStartup:
    68  				c.Check(startupRegistered, jc.IsFalse)
    69  				startupRegistered = true
    70  				waitGroup.Done()
    71  			default:
    72  				c.Errorf("unknown path registered in controller: %s", p)
    73  			}
    74  			return nil
    75  		},
    76  		RemoveHandlerFunc: func(m, p string) {
    77  			c.Check(m, gc.Equals, http.MethodGet)
    78  			switch p {
    79  			case k8sconstants.AgentHTTPPathLiveness:
    80  				c.Check(livenessDeRegistered, jc.IsFalse)
    81  				livenessDeRegistered = true
    82  				waitGroup.Done()
    83  			case k8sconstants.AgentHTTPPathReadiness:
    84  				c.Check(readinessDeRegistered, jc.IsFalse)
    85  				readinessDeRegistered = true
    86  				waitGroup.Done()
    87  			case k8sconstants.AgentHTTPPathStartup:
    88  				c.Check(startupDeRegistered, jc.IsFalse)
    89  				startupDeRegistered = true
    90  				waitGroup.Done()
    91  			default:
    92  				c.Errorf("unknown path registered in controller: %s", p)
    93  			}
    94  		},
    95  	}
    96  
    97  	probes := caasprober.NewCAASProbes()
    98  	probes.Liveness.Probes["test"] = probe.NotImplemented
    99  	probes.Readiness.Probes["test"] = probe.NotImplemented
   100  	probes.Startup.Probes["test"] = probe.NotImplemented
   101  
   102  	controller, err := caasprober.NewController(probes, &mux)
   103  	c.Assert(err, jc.ErrorIsNil)
   104  
   105  	waitGroup.Wait()
   106  	waitGroup.Add(3)
   107  	controller.Kill()
   108  
   109  	waitGroup.Wait()
   110  	err = controller.Wait()
   111  	c.Assert(err, jc.ErrorIsNil)
   112  
   113  	c.Assert(livenessRegistered, jc.IsTrue)
   114  	c.Assert(livenessDeRegistered, jc.IsTrue)
   115  	c.Assert(readinessRegistered, jc.IsTrue)
   116  	c.Assert(readinessDeRegistered, jc.IsTrue)
   117  	c.Assert(startupRegistered, jc.IsTrue)
   118  	c.Assert(startupDeRegistered, jc.IsTrue)
   119  }
   120  
   121  func (s *ControllerSuite) TestControllerNotImplemented(c *gc.C) {
   122  	waitGroup := sync.WaitGroup{}
   123  	waitGroup.Add(3)
   124  
   125  	mux := dummyMux{
   126  		AddHandlerFunc: func(m, p string, h http.Handler) error {
   127  			req := httptest.NewRequest(m, p, nil)
   128  			recorder := httptest.NewRecorder()
   129  			h.ServeHTTP(recorder, req)
   130  			c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusNotImplemented)
   131  			waitGroup.Done()
   132  			return nil
   133  		},
   134  		RemoveHandlerFunc: func(m, p string) {},
   135  	}
   136  
   137  	probes := caasprober.NewCAASProbes()
   138  	probes.Liveness.Probes["test"] = probe.NotImplemented
   139  	probes.Readiness.Probes["test"] = probe.NotImplemented
   140  	probes.Startup.Probes["test"] = probe.NotImplemented
   141  
   142  	controller, err := caasprober.NewController(probes, &mux)
   143  	c.Assert(err, jc.ErrorIsNil)
   144  
   145  	waitGroup.Wait()
   146  	controller.Kill()
   147  	err = controller.Wait()
   148  	c.Assert(err, jc.ErrorIsNil)
   149  }
   150  
   151  func (s *ControllerSuite) TestControllerProbeError(c *gc.C) {
   152  	waitGroup := sync.WaitGroup{}
   153  	waitGroup.Add(3)
   154  
   155  	mux := dummyMux{
   156  		AddHandlerFunc: func(m, p string, h http.Handler) error {
   157  			req := httptest.NewRequest(m, p, nil)
   158  			recorder := httptest.NewRecorder()
   159  			h.ServeHTTP(recorder, req)
   160  			c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusInternalServerError)
   161  			waitGroup.Done()
   162  			return nil
   163  		},
   164  		RemoveHandlerFunc: func(m, p string) {},
   165  	}
   166  
   167  	probeErr := probe.ProberFn(func() (bool, error) {
   168  		return false, errors.New("test error")
   169  	})
   170  
   171  	probes := caasprober.NewCAASProbes()
   172  	probes.Liveness.Probes["test"] = probeErr
   173  	probes.Readiness.Probes["test"] = probeErr
   174  	probes.Startup.Probes["test"] = probeErr
   175  
   176  	controller, err := caasprober.NewController(probes, &mux)
   177  	c.Assert(err, jc.ErrorIsNil)
   178  
   179  	waitGroup.Wait()
   180  	controller.Kill()
   181  	err = controller.Wait()
   182  	c.Assert(err, jc.ErrorIsNil)
   183  }
   184  
   185  func (s *ControllerSuite) TestControllerProbeFail(c *gc.C) {
   186  	waitGroup := sync.WaitGroup{}
   187  	waitGroup.Add(3)
   188  
   189  	mux := dummyMux{
   190  		AddHandlerFunc: func(m, p string, h http.Handler) error {
   191  			req := httptest.NewRequest(m, p, nil)
   192  			recorder := httptest.NewRecorder()
   193  			h.ServeHTTP(recorder, req)
   194  			c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusTeapot)
   195  			waitGroup.Done()
   196  			return nil
   197  		},
   198  		RemoveHandlerFunc: func(m, p string) {},
   199  	}
   200  
   201  	probeFail := probe.ProberFn(func() (bool, error) {
   202  		return false, nil
   203  	})
   204  
   205  	probes := caasprober.NewCAASProbes()
   206  	probes.Liveness.Probes["test"] = probeFail
   207  	probes.Readiness.Probes["test"] = probeFail
   208  	probes.Startup.Probes["test"] = probeFail
   209  
   210  	controller, err := caasprober.NewController(probes, &mux)
   211  	c.Assert(err, jc.ErrorIsNil)
   212  
   213  	waitGroup.Wait()
   214  	controller.Kill()
   215  	err = controller.Wait()
   216  	c.Assert(err, jc.ErrorIsNil)
   217  }
   218  
   219  func (s *ControllerSuite) TestControllerProbePass(c *gc.C) {
   220  	waitGroup := sync.WaitGroup{}
   221  	waitGroup.Add(3)
   222  
   223  	mux := dummyMux{
   224  		AddHandlerFunc: func(m, p string, h http.Handler) error {
   225  			req := httptest.NewRequest(m, p, nil)
   226  			recorder := httptest.NewRecorder()
   227  			h.ServeHTTP(recorder, req)
   228  			c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusOK)
   229  			waitGroup.Done()
   230  			return nil
   231  		},
   232  		RemoveHandlerFunc: func(m, p string) {},
   233  	}
   234  
   235  	probes := caasprober.NewCAASProbes()
   236  	probes.Liveness.Probes["test"] = probe.Success
   237  	probes.Readiness.Probes["test"] = probe.Success
   238  	probes.Startup.Probes["test"] = probe.Success
   239  
   240  	controller, err := caasprober.NewController(probes, &mux)
   241  	c.Assert(err, jc.ErrorIsNil)
   242  
   243  	waitGroup.Wait()
   244  	controller.Kill()
   245  	err = controller.Wait()
   246  	c.Assert(err, jc.ErrorIsNil)
   247  }
   248  
   249  func (s *ControllerSuite) TestControllerProbePassDetailed(c *gc.C) {
   250  	waitGroup := sync.WaitGroup{}
   251  	waitGroup.Add(3)
   252  
   253  	mux := dummyMux{
   254  		AddHandlerFunc: func(m, p string, h http.Handler) error {
   255  			req := httptest.NewRequest(m, p+"?detailed=true", nil)
   256  			recorder := httptest.NewRecorder()
   257  			h.ServeHTTP(recorder, req)
   258  			c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusOK)
   259  			c.Check(recorder.Body.String(), jc.HasPrefix, `+ test
   260  OK: probe`)
   261  			waitGroup.Done()
   262  			return nil
   263  		},
   264  		RemoveHandlerFunc: func(m, p string) {},
   265  	}
   266  
   267  	probes := caasprober.NewCAASProbes()
   268  	probes.Liveness.Probes["test"] = probe.Success
   269  	probes.Readiness.Probes["test"] = probe.Success
   270  	probes.Startup.Probes["test"] = probe.Success
   271  
   272  	controller, err := caasprober.NewController(probes, &mux)
   273  	c.Assert(err, jc.ErrorIsNil)
   274  
   275  	waitGroup.Wait()
   276  	controller.Kill()
   277  	err = controller.Wait()
   278  	c.Assert(err, jc.ErrorIsNil)
   279  }
   280  
   281  func (s *ControllerSuite) TestControllerProbeFailDetailed(c *gc.C) {
   282  	waitGroup := sync.WaitGroup{}
   283  	waitGroup.Add(3)
   284  
   285  	mux := dummyMux{
   286  		AddHandlerFunc: func(m, p string, h http.Handler) error {
   287  			req := httptest.NewRequest(m, p+"?detailed=true", nil)
   288  			recorder := httptest.NewRecorder()
   289  			h.ServeHTTP(recorder, req)
   290  			c.Check(recorder.Result().StatusCode, gc.Equals, http.StatusOK)
   291  			c.Check(recorder.Body.String(), jc.HasPrefix, `- test: test error
   292  Internal Server Error: probe`)
   293  			waitGroup.Done()
   294  			return nil
   295  		},
   296  		RemoveHandlerFunc: func(m, p string) {},
   297  	}
   298  
   299  	probeFail := probe.ProberFn(func() (bool, error) {
   300  		return false, errors.New("test error")
   301  	})
   302  
   303  	probes := caasprober.NewCAASProbes()
   304  	probes.Liveness.Probes["test"] = probeFail
   305  	probes.Readiness.Probes["test"] = probeFail
   306  	probes.Startup.Probes["test"] = probeFail
   307  
   308  	controller, err := caasprober.NewController(probes, &mux)
   309  	c.Assert(err, jc.ErrorIsNil)
   310  
   311  	waitGroup.Wait()
   312  	controller.Kill()
   313  	err = controller.Wait()
   314  	c.Assert(err, jc.ErrorIsNil)
   315  }