diff --git a/pkg/dlx/dlx.go b/pkg/dlx/dlx.go index 885ebbe6..ae9fa876 100644 --- a/pkg/dlx/dlx.go +++ b/pkg/dlx/dlx.go @@ -71,7 +71,8 @@ func NewDLX(parentLogger logger.Logger, options.TargetNameHeader, options.TargetPathHeader, options.TargetPort, - options.MultiTargetStrategy) + options.MultiTargetStrategy, + watcher.GetIngressHostCacheReader()) if err != nil { return nil, errors.Wrap(err, "Failed to create handler") } diff --git a/pkg/dlx/handler.go b/pkg/dlx/handler.go index 9980ecc5..e9a31191 100644 --- a/pkg/dlx/handler.go +++ b/pkg/dlx/handler.go @@ -30,6 +30,7 @@ import ( "sync" "time" + "github.com/v3io/scaler/pkg/ingresscache" "github.com/v3io/scaler/pkg/scalertypes" "github.com/nuclio/errors" @@ -49,6 +50,7 @@ type Handler struct { targetURLCache *cache.LRUExpireCache proxyLock sync.Locker lastProxyErrorTime time.Time + ingressCache ingresscache.IngressHostCacheReader } func NewHandler(parentLogger logger.Logger, @@ -57,7 +59,8 @@ func NewHandler(parentLogger logger.Logger, targetNameHeader string, targetPathHeader string, targetPort int, - multiTargetStrategy scalertypes.MultiTargetStrategy) (Handler, error) { + multiTargetStrategy scalertypes.MultiTargetStrategy, + ingressCache ingresscache.IngressHostCacheReader) (Handler, error) { h := Handler{ logger: parentLogger.GetChild("handler"), resourceStarter: resourceStarter, @@ -69,17 +72,17 @@ func NewHandler(parentLogger logger.Logger, targetURLCache: cache.NewLRUExpireCache(100), proxyLock: &sync.Mutex{}, lastProxyErrorTime: time.Now(), + ingressCache: ingressCache, } h.HandleFunc = h.handleRequest return h, nil } func (h *Handler) handleRequest(res http.ResponseWriter, req *http.Request) { + var path string + var err error var resourceNames []string - responseChannel := make(chan ResourceStatusResult, 1) - defer close(responseChannel) - // first try to see if our request came from ingress controller forwardedHost := req.Header.Get("X-Forwarded-Host") forwardedPort := req.Header.Get("X-Forwarded-Port") @@ -97,15 +100,15 @@ func (h *Handler) handleRequest(res http.ResponseWriter, req *http.Request) { resourceNames = append(resourceNames, resourceName) resourceTargetURLMap[resourceName] = targetURL } else { - targetNameHeaderValue := req.Header.Get(h.targetNameHeader) - path := req.Header.Get(h.targetPathHeader) - if targetNameHeaderValue == "" { - h.logger.WarnWith("When ingress not set, must pass header value", - "missingHeader", h.targetNameHeader) + path, resourceNames, err = h.getPathAndResourceNames(req) + if err != nil { + h.logger.WarnWith("Failed to get resource names and path from request", + "error", err.Error(), + "host", req.Host, + "path", h.getRequestURLPath(req)) res.WriteHeader(http.StatusBadRequest) return } - resourceNames = strings.Split(targetNameHeaderValue, ",") for _, resourceName := range resourceNames { targetURL, status := h.parseTargetURL(resourceName, path) if targetURL == nil { @@ -163,6 +166,43 @@ func (h *Handler) handleRequest(res http.ResponseWriter, req *http.Request) { proxy.ServeHTTP(res, req) } +func (h *Handler) getPathAndResourceNames(req *http.Request) (string, []string, error) { + // first try to get the resource names and path from the ingress cache + path, resourceNames, err := h.getValuesFromCache(req) + if err == nil { + return path, resourceNames, nil + } + + h.logger.DebugWith("Failed to get resource names from ingress cache, trying to extract from the request headers", + "host", req.Host, + "path", h.getRequestURLPath(req), + "error", err.Error()) + + // old implementation for backward compatibility + targetNameHeaderValue := req.Header.Get(h.targetNameHeader) + path = req.Header.Get(h.targetPathHeader) + if targetNameHeaderValue == "" { + return "", nil, errors.New("No target name header found") + } + resourceNames = strings.Split(targetNameHeaderValue, ",") + return path, resourceNames, nil +} + +func (h *Handler) getValuesFromCache(req *http.Request) (string, []string, error) { + host := req.Host + path := h.getRequestURLPath(req) + resourceNames, err := h.ingressCache.Get(host, path) + if err != nil { + return "", nil, errors.New("Failed to get resource names from ingress cache") + } + + if len(resourceNames) == 0 { + return "", nil, errors.New("No resources found in ingress cache") + } + + return path, resourceNames, nil +} + func (h *Handler) parseTargetURL(resourceName, path string) (*url.URL, int) { serviceName, err := h.resourceScaler.ResolveServiceName(scalertypes.Resource{Name: resourceName}) if err != nil { @@ -178,17 +218,17 @@ func (h *Handler) parseTargetURL(resourceName, path string) (*url.URL, int) { } func (h *Handler) startResources(resourceNames []string) *ResourceStatusResult { - responseChannel := make(chan ResourceStatusResult, len(resourceNames)) - defer close(responseChannel) + responseChan := make(chan ResourceStatusResult, len(resourceNames)) + defer close(responseChan) // Start all resources in separate go routines for _, resourceName := range resourceNames { - go h.resourceStarter.handleResourceStart(resourceName, responseChannel) + go h.resourceStarter.handleResourceStart(resourceName, responseChan) } // Wait for all resources to finish starting for range resourceNames { - statusResult := <-responseChannel + statusResult := <-responseChan if statusResult.Error != nil { h.logger.WarnWith("Failed to start resource", @@ -230,3 +270,10 @@ func (h *Handler) URLBadParse(resourceName string, err error) int { "err", errors.GetErrorStackString(err, 10)) return http.StatusBadRequest } + +func (h *Handler) getRequestURLPath(req *http.Request) string { + if req.URL != nil { + return req.URL.Path + } + return "" +} diff --git a/pkg/dlx/handler_test.go b/pkg/dlx/handler_test.go new file mode 100644 index 00000000..8693bc8f --- /dev/null +++ b/pkg/dlx/handler_test.go @@ -0,0 +1,321 @@ +package dlx + +import ( + "errors" + "net/http" + "net/http/httptest" + "net/url" + "strconv" + "testing" + "time" + + "github.com/v3io/scaler/pkg/ingresscache" + "github.com/v3io/scaler/pkg/kube" + resourcescalerMock "github.com/v3io/scaler/pkg/resourcescaler/mock" + "github.com/v3io/scaler/pkg/scalertypes" + + "github.com/nuclio/logger" + nucliozap "github.com/nuclio/zap" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/suite" +) + +type HandlerTestSuite struct { + suite.Suite + logger logger.Logger + starter *ResourceStarter + scaler *resourcescalerMock.ResourceScaler + httpServer *httptest.Server + backendHost string + backendPort int +} + +func (suite *HandlerTestSuite) SetupSuite() { + var err error + suite.logger, err = nucliozap.NewNuclioZapTest("test") + suite.Require().NoError(err) +} + +func (suite *HandlerTestSuite) SetupTest() { + suite.scaler = &resourcescalerMock.ResourceScaler{} + suite.starter = &ResourceStarter{ + logger: suite.logger, + scaler: suite.scaler, + resourceReadinessTimeout: 3 * time.Second, + } + allowedPaths := map[string]struct{}{ + "/test/path/test/path": {}, + "/test/path/to/multiple/test/path/to/multiple": {}, + } + // Start a test server that always returns 200 + suite.httpServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if _, exists := allowedPaths[r.URL.Path]; exists { + w.WriteHeader(http.StatusOK) + } else { + w.WriteHeader(http.StatusBadRequest) + } + })) + + backendURL, _ := url.Parse(suite.httpServer.URL) + suite.backendHost = backendURL.Hostname() + backendPort := backendURL.Port() + if backendPort == "" { + backendPort = "8080" // Default HTTP port + } + backendPortInt, err := strconv.Atoi(backendPort) + suite.Require().NoError(err) + suite.backendPort = backendPortInt +} + +func (suite *HandlerTestSuite) TearDownTest() { + if suite.httpServer != nil { + suite.httpServer.Close() + } +} + +func (suite *HandlerTestSuite) TestHandleRequest() { + for _, testCase := range []struct { + name string + resolveServiceNameErr error + initialCachedData *kube.IngressValue + reqHeaders map[string]string + reqHost string + reqPath string + expectedStatus int + }{ + { + name: "No request headers, host and path found in ingress cache", + resolveServiceNameErr: nil, + initialCachedData: &kube.IngressValue{ + Host: "www.example.com", + Path: "test/path", + Targets: []string{"test-targets-name-1"}, + }, + reqHost: "www.example.com", + reqPath: "test/path", + expectedStatus: http.StatusOK, + }, { + name: "No request headers, multiple targets found in ingress cache", + resolveServiceNameErr: nil, + initialCachedData: &kube.IngressValue{ + Host: "www.example.com", + Path: "test/path/to/multiple", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, + }, + reqHost: "www.example.com", + reqPath: "test/path/to/multiple", + expectedStatus: http.StatusOK, + }, + { + name: "No request headers, not found in ingress cache", + resolveServiceNameErr: nil, + initialCachedData: nil, + reqHost: "unknown", + reqPath: "/notfound", + expectedStatus: http.StatusBadRequest, + }, + { + name: "No request headers, scaler fails", + resolveServiceNameErr: errors.New("fail"), + initialCachedData: &kube.IngressValue{ + Host: "www.example.com", + Path: "test/path", + Targets: []string{"test-targets-name-1"}, + }, + reqHost: "www.example.com", + reqPath: "test/path", + expectedStatus: http.StatusInternalServerError, + }, + { + name: "Request headers flow", + reqHeaders: map[string]string{ + "X-Forwarded-Host": "127.0.0.1", + "X-Original-Uri": "test/path", + "X-Resource-Name": "test-targets-name-1", + }, + reqHost: "www.example.com", + reqPath: "test/path", + expectedStatus: http.StatusOK, + }, + } { + suite.Run(testCase.name, func() { + // test case setup + suite.setScalerMocksBasedOnTestCase(testCase.name, testCase.resolveServiceNameErr) + + testHandler, err := suite.createTestHandlerAndInitTestCache(suite.backendPort, testCase.initialCachedData) + suite.Require().NoError(err) + testRequest := suite.createTestHTTPRequest(testCase.name, testCase.reqHeaders, testCase.reqHost, testCase.reqPath) + testResponse := httptest.NewRecorder() + + // call the testHandler + testHandler.handleRequest(testResponse, testRequest) + + // validate the response + suite.Require().Equal(testCase.expectedStatus, testResponse.Code) + suite.scaler.AssertExpectations(suite.T()) + }) + } +} + +func (suite *HandlerTestSuite) TestGetPathAndResourceNames() { + for _, testCase := range []struct { + name string + errMsg string + initialCachedData *kube.IngressValue + reqHeaders map[string]string + reqHost string + reqPath string + expectErr bool + expectedPath string + expectedResourceNames []string + }{ + { + name: "No request headers, host and path found in ingress cache", + initialCachedData: &kube.IngressValue{ + Host: "www.example.com", + Path: "test/path", + Targets: []string{"test-targets-name-1"}, + }, + reqHost: "www.example.com", + reqPath: "test/path", + expectedPath: "test/path", + expectedResourceNames: []string{"test-targets-name-1"}, + }, { + name: "request headers, host and path did not found in ingress cache", + reqHost: "www.example.com", + reqPath: "test/path", + expectedPath: "test/path", + expectedResourceNames: []string{"test-targets-name-1"}, + reqHeaders: map[string]string{ + "X-Resource-Name": "test-targets-name-1", + "X-Resource-Path": "test/path", + }, + }, { + name: "Missing both request headers and host and path did not found in ingress cache", + reqHost: "www.example.com", + reqPath: "test/path", + expectErr: true, + errMsg: "No target name header found", + }, { + name: "Both request headers and found in ingress cache, cache results should be taken", + reqHost: "www.example.com", + reqPath: "test/path", + initialCachedData: &kube.IngressValue{ + Host: "www.example.com", + Path: "test/path", + Targets: []string{"test-targets-from-cache"}, + }, + reqHeaders: map[string]string{ + "X-Resource-Name": "test-targets-from-headers", + "X-Resource-Path": "test/path", + }, + expectedPath: "test/path", + expectedResourceNames: []string{"test-targets-from-cache"}, + }, + { + name: "No request headers, missing request.URL", + initialCachedData: &kube.IngressValue{ + Host: "www.example.com", + Path: "test/path", + Targets: []string{"test-targets-name-1"}, + }, + reqHost: "www.example.com", + reqPath: "test/path", + expectErr: true, + errMsg: "No target name header found", + }, + } { + suite.Run(testCase.name, func() { + // test case setup + testHandler, err := suite.createTestHandlerAndInitTestCache(suite.backendPort, testCase.initialCachedData) + suite.Require().NoError(err) + testRequest := suite.createTestHTTPRequest(testCase.name, testCase.reqHeaders, testCase.reqHost, testCase.reqPath) + resultPath, resultResourceNames, err := testHandler.getPathAndResourceNames(testRequest) + + // validate the result + if testCase.expectErr { + suite.Require().Error(err) + suite.Require().ErrorContains(err, testCase.errMsg) + } else { + suite.Require().NoError(err) + suite.Require().Equal(testCase.expectedPath, resultPath) + suite.Require().Equal(testCase.expectedResourceNames, resultResourceNames) + } + }) + } +} + +// --- HandlerTestSuite suite methods --- + +func (suite *HandlerTestSuite) createTestHandlerAndInitTestCache(targetPort int, initialCachedData *kube.IngressValue) (Handler, error) { + testIngressCache := ingresscache.NewIngressCache(suite.logger) + if initialCachedData != nil { + if err := testIngressCache.Set(initialCachedData.Host, initialCachedData.Path, initialCachedData.Targets); err != nil { + return Handler{}, err + } + } + + return NewHandler( + suite.logger, + suite.starter, + suite.scaler, + "X-Resource-Name", + "X-Resource-Path", + targetPort, + scalertypes.MultiTargetStrategyPrimary, + testIngressCache, + ) +} + +func (suite *HandlerTestSuite) createTestHTTPRequest( + testName string, + reqHeaders map[string]string, + reqHost string, + reqPath string, +) *http.Request { + req := httptest.NewRequest("GET", "/", nil) + if reqHost != "" { + req.Host = reqHost + } + if reqPath != "" { + req.URL.Path = reqPath + } + + if len(reqHeaders) != 0 { + // pull X-Forwarded-Host from suite because it's not yet set during test case creation + reqHeaders["X-Forwarded-Port"] = strconv.Itoa(suite.backendPort) + } + + for k, v := range reqHeaders { + req.Header.Set(k, v) + } + + switch testName { + case "No request headers, missing request.URL": + req.URL = nil + default: + } + + return req +} + +func (suite *HandlerTestSuite) setScalerMocksBasedOnTestCase( + testName string, + resolveServiceNameErr error, +) { + suite.scaler.ExpectedCalls = nil + switch testName { + case "No request headers, scaler fails": + suite.scaler.On("ResolveServiceName", mock.Anything).Return(suite.backendHost, resolveServiceNameErr) + case "No request headers, not found in ingress cache": + case "Request headers flow": + suite.scaler.On("SetScaleCtx", mock.Anything, mock.Anything, mock.Anything).Return(nil) + default: + suite.scaler.On("ResolveServiceName", mock.Anything).Return(suite.backendHost, resolveServiceNameErr) + suite.scaler.On("SetScaleCtx", mock.Anything, mock.Anything, mock.Anything).Return(nil) + } +} + +func TestHandlerTestSuite(t *testing.T) { + suite.Run(t, new(HandlerTestSuite)) +} diff --git a/pkg/kube/ingress.go b/pkg/kube/ingress.go index a9090a26..60c8e949 100644 --- a/pkg/kube/ingress.go +++ b/pkg/kube/ingress.go @@ -35,11 +35,11 @@ import ( "k8s.io/client-go/tools/cache" ) -type ingressValue struct { - name string - host string - path string - targets []string +type IngressValue struct { + Name string + Host string + Path string + Targets []string } // IngressWatcher watches for changes in Kubernetes Ingress resources and updates the ingress cache accordingly @@ -133,22 +133,22 @@ func (iw *IngressWatcher) AddHandler(obj interface{}) { return } - if err := iw.cache.Set(ingress.host, ingress.path, ingress.targets); err != nil { + if err := iw.cache.Set(ingress.Host, ingress.Path, ingress.Targets); err != nil { iw.logger.WarnWith("Add ingress handler failure - failed to add the new value to ingress cache", "error", err.Error(), "object", obj, - "ingressName", ingress.name, - "host", ingress.host, - "path", ingress.path, - "targets", ingress.targets) + "ingressName", ingress.Name, + "host", ingress.Host, + "path", ingress.Path, + "targets", ingress.Targets) return } iw.logger.DebugWith("Add ingress handler - successfully added ingress to cache", - "ingressName", ingress.name, - "host", ingress.host, - "path", ingress.path, - "targets", ingress.targets) + "ingressName", ingress.Name, + "host", ingress.Host, + "path", ingress.Path, + "targets", ingress.Targets) } func (iw *IngressWatcher) UpdateHandler(oldObj, newObj interface{}) { @@ -187,34 +187,34 @@ func (iw *IngressWatcher) UpdateHandler(oldObj, newObj interface{}) { } // if the host or path has changed, we need to delete the old entry - if oldIngress.host != newIngress.host || oldIngress.path != newIngress.path { - if err := iw.cache.Delete(oldIngress.host, oldIngress.path, oldIngress.targets); err != nil { + if oldIngress.Host != newIngress.Host || oldIngress.Path != newIngress.Path { + if err := iw.cache.Delete(oldIngress.Host, oldIngress.Path, oldIngress.Targets); err != nil { iw.logger.WarnWith("Update ingress handler failure - failed to delete old ingress", "error", err.Error(), - "ingressName", oldIngress.name, + "ingressName", oldIngress.Name, "object", oldObj, - "host", oldIngress.host, - "path", oldIngress.path, - "targets", oldIngress.targets) + "host", oldIngress.Host, + "path", oldIngress.Path, + "targets", oldIngress.Targets) } } - if err := iw.cache.Set(newIngress.host, newIngress.path, newIngress.targets); err != nil { + if err := iw.cache.Set(newIngress.Host, newIngress.Path, newIngress.Targets); err != nil { iw.logger.WarnWith("Update ingress handler failure - failed to add the new value", "error", err.Error(), "object", newObj, - "ingressName", newIngress.name, - "host", newIngress.host, - "path", newIngress.path, - "targets", newIngress.targets) + "ingressName", newIngress.Name, + "host", newIngress.Host, + "path", newIngress.Path, + "targets", newIngress.Targets) return } iw.logger.DebugWith("Update ingress handler - successfully updated ingress in cache", - "ingressName", newIngress.name, - "host", newIngress.host, - "path", newIngress.path, - "targets", newIngress.targets) + "ingressName", newIngress.Name, + "host", newIngress.Host, + "path", newIngress.Path, + "targets", newIngress.Targets) } func (iw *IngressWatcher) DeleteHandler(obj interface{}) { @@ -225,28 +225,28 @@ func (iw *IngressWatcher) DeleteHandler(obj interface{}) { return } - if err := iw.cache.Delete(ingress.host, ingress.path, ingress.targets); err != nil { + if err := iw.cache.Delete(ingress.Host, ingress.Path, ingress.Targets); err != nil { iw.logger.WarnWith("Delete ingress handler failure - failed delete from cache", "error", err.Error(), "object", obj, - "ingressName", ingress.name, - "host", ingress.host, - "path", ingress.path, - "targets", ingress.targets) + "ingressName", ingress.Name, + "host", ingress.Host, + "path", ingress.Path, + "targets", ingress.Targets) return } iw.logger.DebugWith("Delete ingress handler - successfully deleted ingress from cache", - "ingressName", ingress.name, - "host", ingress.host, - "path", ingress.path, - "targets", ingress.targets) + "ingressName", ingress.Name, + "host", ingress.Host, + "path", ingress.Path, + "targets", ingress.Targets) } // --- internal methods --- // extractValuesFromIngressResource extracts the relevant values from a Kubernetes Ingress resource -func (iw *IngressWatcher) extractValuesFromIngressResource(obj interface{}) (*ingressValue, error) { +func (iw *IngressWatcher) extractValuesFromIngressResource(obj interface{}) (*IngressValue, error) { ingress, ok := obj.(*networkingv1.Ingress) if !ok { return nil, errors.New("Failed to cast object to Ingress") @@ -271,11 +271,11 @@ func (iw *IngressWatcher) extractValuesFromIngressResource(obj interface{}) (*in return nil, errors.Wrap(err, "Failed to extract path from ingress") } - return &ingressValue{ - host: host, - path: path, - targets: targets, - name: ingress.Name, + return &IngressValue{ + Host: host, + Path: path, + Targets: targets, + Name: ingress.Name, }, nil } diff --git a/pkg/kube/ingress_test.go b/pkg/kube/ingress_test.go index 93676fed..134b78b2 100644 --- a/pkg/kube/ingress_test.go +++ b/pkg/kube/ingress_test.go @@ -64,47 +64,47 @@ func (suite *IngressWatcherTestSuite) SetupTest() { func (suite *IngressWatcherTestSuite) TestAddHandler() { for _, testCase := range []struct { name string - testArgs ingressValue + testArgs IngressValue expectedResult []string - initialCachedData *ingressValue + initialCachedData *IngressValue errorMessage string expectError bool }{ { name: "Add PairTarget", - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, expectedResult: []string{"test-targets-name-1", "test-targets-name-2"}, }, { name: "Add SingleTarget", - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1"}, }, expectedResult: []string{"test-targets-name-1"}, }, { name: "Add SingleTarget with different name to the same host and path", - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-2"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-2"}, }, expectedResult: []string{"test-targets-name-2"}, - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1"}, }, }, { name: "bad input- should fail", - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-2"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-2"}, }, expectedResult: []string{}, expectError: true, @@ -116,20 +116,20 @@ func (suite *IngressWatcherTestSuite) TestAddHandler() { testIngressWatcher, err := suite.createTestIngressWatcher() suite.Require().NoError(err) - testObj = suite.createDummyIngress(testCase.testArgs.host, testCase.testArgs.path, "1", testCase.testArgs.targets) + testObj = suite.createDummyIngress(testCase.testArgs.Host, testCase.testArgs.Path, "1", testCase.testArgs.Targets) if testCase.expectError { testObj = &networkingv1.IngressSpec{} } if testCase.initialCachedData != nil { - err = testIngressWatcher.cache.Set(testCase.initialCachedData.host, testCase.initialCachedData.path, testCase.initialCachedData.targets) + err = testIngressWatcher.cache.Set(testCase.initialCachedData.Host, testCase.initialCachedData.Path, testCase.initialCachedData.Targets) suite.Require().NoError(err) } testIngressWatcher.AddHandler(testObj) // get the targets from the cache and compare values - resultTargetNames, err := testIngressWatcher.cache.Get(testCase.testArgs.host, testCase.testArgs.path) + resultTargetNames, err := testIngressWatcher.cache.Get(testCase.testArgs.Host, testCase.testArgs.Path) if testCase.expectError { suite.Require().Error(err) suite.Require().ErrorContains(err, testCase.errorMessage) @@ -146,9 +146,9 @@ func (suite *IngressWatcherTestSuite) TestUpdateHandler() { for _, testCase := range []struct { name string expectedResults []expectedResult - initialCachedData *ingressValue - testOldObj ingressValue - testNewObj ingressValue + initialCachedData *IngressValue + testOldObj IngressValue + testNewObj IngressValue OldObjVersion string newObjVersion string }{ @@ -161,22 +161,22 @@ func (suite *IngressWatcherTestSuite) TestUpdateHandler() { targets: []string{"test-targets-name-1", "test-targets-name-3"}, }, }, - testOldObj: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testOldObj: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, OldObjVersion: "1", - testNewObj: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-3"}, + testNewObj: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-3"}, }, newObjVersion: "2", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, }, { name: "Update PairTarget - same ResourceVersion, no change in targets", @@ -187,40 +187,40 @@ func (suite *IngressWatcherTestSuite) TestUpdateHandler() { targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, }, - testOldObj: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testOldObj: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, - testNewObj: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-3"}, + testNewObj: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-3"}, }, OldObjVersion: "1", newObjVersion: "1", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, }, { name: "Update PairTarget - different path- should Delete old targets", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, - testOldObj: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testOldObj: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, OldObjVersion: "1", - testNewObj: ingressValue{ - host: "www.example.com", - path: "/another/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testNewObj: IngressValue{ + Host: "www.example.com", + Path: "/another/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, newObjVersion: "2", expectedResults: []expectedResult{ @@ -237,21 +237,21 @@ func (suite *IngressWatcherTestSuite) TestUpdateHandler() { }, }, { name: "Update PairTarget - different host- should Delete old targets", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, - testOldObj: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testOldObj: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, OldObjVersion: "1", - testNewObj: ingressValue{ - host: "www.google.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testNewObj: IngressValue{ + Host: "www.google.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, newObjVersion: "2", expectedResults: []expectedResult{ @@ -272,11 +272,11 @@ func (suite *IngressWatcherTestSuite) TestUpdateHandler() { testIngressWatcher, err := suite.createTestIngressWatcher() suite.Require().NoError(err) - testOldObj := suite.createDummyIngress(testCase.testOldObj.host, testCase.testOldObj.path, testCase.OldObjVersion, testCase.testOldObj.targets) - testNewObj := suite.createDummyIngress(testCase.testNewObj.host, testCase.testNewObj.path, testCase.newObjVersion, testCase.testNewObj.targets) + testOldObj := suite.createDummyIngress(testCase.testOldObj.Host, testCase.testOldObj.Path, testCase.OldObjVersion, testCase.testOldObj.Targets) + testNewObj := suite.createDummyIngress(testCase.testNewObj.Host, testCase.testNewObj.Path, testCase.newObjVersion, testCase.testNewObj.Targets) if testCase.initialCachedData != nil { - err = testIngressWatcher.cache.Set(testCase.initialCachedData.host, testCase.initialCachedData.path, testCase.initialCachedData.targets) + err = testIngressWatcher.cache.Set(testCase.initialCachedData.Host, testCase.initialCachedData.Path, testCase.initialCachedData.Targets) suite.Require().NoError(err) } @@ -301,23 +301,23 @@ func (suite *IngressWatcherTestSuite) TestUpdateHandler() { func (suite *IngressWatcherTestSuite) TestDeleteHandler() { for _, testCase := range []struct { name string - testArgs ingressValue + testArgs IngressValue expectedResult expectedResult - initialCachedData *ingressValue + initialCachedData *IngressValue errorMessage string expectError bool }{ { name: "Delete PairTarget", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1", "test-targets-name-2"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1", "test-targets-name-2"}, }, expectedResult: expectedResult{ host: "www.example.com", @@ -328,15 +328,15 @@ func (suite *IngressWatcherTestSuite) TestDeleteHandler() { }, }, { name: "Delete SingleTarget", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1"}, }, - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1"}, }, expectedResult: expectedResult{ host: "www.example.com", @@ -347,15 +347,15 @@ func (suite *IngressWatcherTestSuite) TestDeleteHandler() { }, }, { name: "bad input- should fail and keep the cache as is", - initialCachedData: &ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-1"}, + initialCachedData: &IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-1"}, }, - testArgs: ingressValue{ - host: "www.example.com", - path: "/test/path", - targets: []string{"test-targets-name-2"}, + testArgs: IngressValue{ + Host: "www.example.com", + Path: "/test/path", + Targets: []string{"test-targets-name-2"}, }, expectedResult: expectedResult{ host: "www.example.com", @@ -371,14 +371,14 @@ func (suite *IngressWatcherTestSuite) TestDeleteHandler() { testIngressWatcher, err := suite.createTestIngressWatcher() suite.Require().NoError(err) - testObj = suite.createDummyIngress(testCase.testArgs.host, testCase.testArgs.path, "1", testCase.testArgs.targets) + testObj = suite.createDummyIngress(testCase.testArgs.Host, testCase.testArgs.Path, "1", testCase.testArgs.Targets) if testCase.expectError { testObj = &networkingv1.IngressSpec{} } if testCase.initialCachedData != nil { - err = testIngressWatcher.cache.Set(testCase.initialCachedData.host, testCase.initialCachedData.path, testCase.initialCachedData.targets) + err = testIngressWatcher.cache.Set(testCase.initialCachedData.Host, testCase.initialCachedData.Path, testCase.initialCachedData.Targets) suite.Require().NoError(err) }