From b3b886a942de37e861b6978c68ded1762462f058 Mon Sep 17 00:00:00 2001 From: Tit Petric Date: Sun, 16 Feb 2025 17:41:20 +0100 Subject: [PATCH] Remove dnsmock from test, implement NewTest, functional options, sort lifecycle into test.go --- gateway/reverse_proxy_test.go | 6 -- gateway/test.go | 181 ++++++++++++++++++++++++++++++++++ gateway/testutil.go | 148 --------------------------- 3 files changed, 181 insertions(+), 154 deletions(-) create mode 100644 gateway/test.go diff --git a/gateway/reverse_proxy_test.go b/gateway/reverse_proxy_test.go index c823923fc06..0d3ad81bf87 100644 --- a/gateway/reverse_proxy_test.go +++ b/gateway/reverse_proxy_test.go @@ -140,7 +140,6 @@ type configTestReverseProxyDnsCache struct { } func (s *Test) flakySetupTestReverseProxyDnsCache(cfg *configTestReverseProxyDnsCache) func() { - pullDomains := s.MockHandle.PushDomains(cfg.etcHostsMap, nil) s.Gw.dnsCacheManager.InitDNSCaching( time.Duration(cfg.dnsConfig.TTL)*time.Second, time.Duration(cfg.dnsConfig.CheckInterval)*time.Second) @@ -151,7 +150,6 @@ func (s *Test) flakySetupTestReverseProxyDnsCache(cfg *configTestReverseProxyDns s.Gw.SetConfig(globalConf) return func() { - pullDomains() s.Gw.dnsCacheManager.DisposeCache() globalConf.HttpServerOptions.EnableWebSockets = enableWebSockets s.Gw.SetConfig(globalConf) @@ -188,11 +186,7 @@ func TestReverseProxyDnsCache(t *testing.T) { ) ts := StartTest(nil) - ts.MockHandle, _ = test.InitDNSMock(etcHostsMap, nil) defer ts.Close() - defer func() { - _ = ts.MockHandle.ShutdownDnsMock() - }() tearDown := ts.flakySetupTestReverseProxyDnsCache(&configTestReverseProxyDnsCache{t, etcHostsMap, config.DnsCacheConfig{ diff --git a/gateway/test.go b/gateway/test.go new file mode 100644 index 00000000000..ca87bb704e0 --- /dev/null +++ b/gateway/test.go @@ -0,0 +1,181 @@ +package gateway + +import ( + "context" + "net/http" + "testing" + "time" + + "github.com/gorilla/mux" + + "github.com/TykTechnologies/tyk/config" + "github.com/TykTechnologies/tyk/test" +) + +type Test struct { + URL string + testRunner *test.HTTPTestRunner + // GlobalConfig deprecate this and instead use GW.getConfig() + GlobalConfig config.Config + config TestConfig + Gw *Gateway `json:"-"` + HttpHandler *http.Server + TestServerRouter *mux.Router + + ctx context.Context + cancel context.CancelFunc + + dynamicHandlers map[string]http.HandlerFunc + + Parent testing.TB +} + +type TestConfig struct { + SeparateControlAPI bool + Delay time.Duration + HotReload bool + overrideDefaults bool + CoprocessConfig config.CoProcessConfig +} + +type TestOption func(*Test) + +func NewTest(tb testing.TB, genConf func(*config.Config), opts ...TestOption) *Test { + tb.Helper() + + t := &Test{ + Parent: tb, + dynamicHandlers: make(map[string]http.HandlerFunc), + } + + for _, optfn := range opts { + optfn(t) + } + + t.Gw = t.start(genConf) + + tb.Cleanup(t.Close) + + return t +} + +func NewTestConfigOption(conf TestConfig) func(*Test) { + return func(t *Test) { + t.config = conf + } +} + +// Start is the root event point where a gateway object is created, and +// can enforce lifecycle via the *Test objects, and TestOption implementation. +// For example, if somebody wanted to have some default options set up, +// one could set a timeout by implementing: +// +// - `func NewTestTimeoutOption(d time.Duration) func(*Test)` +// +// To use, it should be passed to NewTest as an argument. A default timeout +// may be implemented in the future and set from NewTest as well. +func (s *Test) start(genConf func(globalConf *config.Config)) *Gateway { + // init and create gw + ctx, cancel := context.WithCancel(context.Background()) + + log.Info("starting test") + + s.ctx = ctx + s.cancel = func() { + cancel() + log.Info("Cancelling test context") + } + + gw := s.newGateway(genConf) + gw.setupPortsWhitelist() + gw.startServer() + gw.setupGlobals() + + // Set up a default org manager so we can traverse non-live paths + if !gw.GetConfig().SupressDefaultOrgStore { + gw.DefaultOrgStore.Init(gw.getGlobalStorageHandler("orgkey.", false)) + gw.DefaultQuotaStore.Init(gw.getGlobalStorageHandler("orgkey.", false)) + } + + s.GlobalConfig = gw.GetConfig() + + scheme := "http://" + if s.GlobalConfig.HttpServerOptions.UseSSL { + scheme = "https://" + } + + s.URL = scheme + gw.DefaultProxyMux.getProxy(gw.GetConfig().ListenPort, gw.GetConfig()).listener.Addr().String() + + s.testRunner = &test.HTTPTestRunner{ + RequestBuilder: func(tc *test.TestCase) (*http.Request, error) { + tc.BaseURL = s.URL + if tc.ControlRequest { + if s.config.SeparateControlAPI { + tc.BaseURL = scheme + s.controlProxy().listener.Addr().String() + } else if s.GlobalConfig.ControlAPIHostname != "" { + tc.Domain = s.GlobalConfig.ControlAPIHostname + } + } + r, err := test.NewRequest(tc) + + if tc.AdminAuth { + r = s.withAuth(r) + } + + if s.config.Delay > 0 { + tc.Delay = s.config.Delay + } + + return r, err + }, + Do: test.HttpServerRunner(), + } + + return gw +} + +// Close is the shutdown lifecycle for a gateway integration test w/ storage. +func (s *Test) Close() { + defer s.cancel() + + for _, p := range s.Gw.DefaultProxyMux.proxies { + if p.listener != nil { + p.listener.Close() + } + } + + gwConfig := s.Gw.GetConfig() + + s.Gw.DefaultProxyMux.swap(&proxyMux{}, s.Gw) + if s.config.SeparateControlAPI { + gwConfig.ControlAPIPort = 0 + s.Gw.SetConfig(gwConfig) + } + + // if jsvm enabled we need to unmount to prevent high memory consumption + if s.Gw.GetConfig().EnableJSVM { + s.Gw.GlobalEventsJSVM.VM = nil + } + + ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err := s.HttpHandler.Shutdown(ctxShutDown) + if err != nil { + log.WithError(err).Error("shutting down the http handler") + } else { + log.Info("server exited properly") + } + + s.Gw.Analytics.Stop() + s.Gw.ReloadTestCase.StopTicker() + s.Gw.GlobalHostChecker.StopPoller() + s.Gw.NewRelicApplication.Shutdown(5 * time.Second) + + err = s.RemoveApis() + if err != nil { + log.WithError(err).Error("could not remove apis") + } + + s.Gw.cacheClose() +} diff --git a/gateway/testutil.go b/gateway/testutil.go index 79f75901084..4a5cdee4f8d 100644 --- a/gateway/testutil.go +++ b/gateway/testutil.go @@ -64,9 +64,6 @@ var ( // Used to store the test bundles: testMiddlewarePath, _ = ioutil.TempDir("", "tyk-middleware-path") - - EnableTestDNSMock = false - MockHandle *test.DnsMockHandle ) // ReloadMachinery is a helper struct to use when writing tests that do manual @@ -243,16 +240,6 @@ func InitTestMain(ctx context.Context, m *testing.M) int { bundleBackoffMultiplier = 0 bundleMaxBackoffRetries = 0 - if EnableTestDNSMock { - var errMock error - MockHandle, errMock = test.InitDNSMock(test.DomainsToAddresses, nil) - if errMock != nil { - panic(errMock) - } - - defer MockHandle.ShutdownDnsMock() - } - exitCode := m.Run() return exitCode @@ -1000,32 +987,6 @@ func firstVals(vals map[string][]string) map[string]string { return m } -type TestConfig struct { - SeparateControlAPI bool - Delay time.Duration - HotReload bool - overrideDefaults bool - CoprocessConfig config.CoProcessConfig - EnableTestDNSMock bool -} - -type Test struct { - URL string - testRunner *test.HTTPTestRunner - // GlobalConfig deprecate this and instead use GW.getConfig() - GlobalConfig config.Config - config TestConfig - Gw *Gateway `json:"-"` - HttpHandler *http.Server - TestServerRouter *mux.Router - MockHandle *test.DnsMockHandle - - ctx context.Context - cancel context.CancelFunc - - dynamicHandlers map[string]http.HandlerFunc -} - type SlaveDataCenter struct { SlaveOptions config.SlaveOptionsConfig Redis config.StorageOptionsConf @@ -1036,8 +997,6 @@ func StartTest(genConf func(globalConf *config.Config), testConfig ...TestConfig dynamicHandlers: make(map[string]http.HandlerFunc), } - // DNS mock enabled by default - t.config.EnableTestDNSMock = false if len(testConfig) > 0 { t.config = testConfig[0] } @@ -1047,66 +1006,6 @@ func StartTest(genConf func(globalConf *config.Config), testConfig ...TestConfig return t } -func (s *Test) start(genConf func(globalConf *config.Config)) *Gateway { - // init and create gw - ctx, cancel := context.WithCancel(context.Background()) - - log.Info("starting test") - - s.ctx = ctx - s.cancel = func() { - cancel() - log.Info("Cancelling test context") - } - - gw := s.newGateway(genConf) - gw.setupPortsWhitelist() - gw.startServer() - gw.setupGlobals() - - // Set up a default org manager so we can traverse non-live paths - if !gw.GetConfig().SupressDefaultOrgStore { - gw.DefaultOrgStore.Init(gw.getGlobalStorageHandler("orgkey.", false)) - gw.DefaultQuotaStore.Init(gw.getGlobalStorageHandler("orgkey.", false)) - } - - s.GlobalConfig = gw.GetConfig() - - scheme := "http://" - if s.GlobalConfig.HttpServerOptions.UseSSL { - scheme = "https://" - } - - s.URL = scheme + gw.DefaultProxyMux.getProxy(gw.GetConfig().ListenPort, gw.GetConfig()).listener.Addr().String() - - s.testRunner = &test.HTTPTestRunner{ - RequestBuilder: func(tc *test.TestCase) (*http.Request, error) { - tc.BaseURL = s.URL - if tc.ControlRequest { - if s.config.SeparateControlAPI { - tc.BaseURL = scheme + s.controlProxy().listener.Addr().String() - } else if s.GlobalConfig.ControlAPIHostname != "" { - tc.Domain = s.GlobalConfig.ControlAPIHostname - } - } - r, err := test.NewRequest(tc) - - if tc.AdminAuth { - r = s.withAuth(r) - } - - if s.config.Delay > 0 { - tc.Delay = s.config.Delay - } - - return r, err - }, - Do: test.HttpServerRunner(), - } - - return gw -} - func (s *Test) AddDynamicHandler(path string, handlerFunc http.HandlerFunc) { path = strings.Trim(path, "/") s.dynamicHandlers[path] = handlerFunc @@ -1135,8 +1034,6 @@ func (s *Test) newGateway(genConf func(globalConf *config.Config)) *Gateway { gw.setTestMode(true) gw.ConnectionWatcher = httputil.NewConnectionWatcher() - s.MockHandle = MockHandle - var err error gwConfig.Storage.Database = mathrand.Intn(15) gwConfig.AppPath, err = ioutil.TempDir("", "tyk-test-") @@ -1281,51 +1178,6 @@ func (s *Test) ReloadGatewayProxy() { s.Gw.startServer() } -func (s *Test) Close() { - defer s.cancel() - - for _, p := range s.Gw.DefaultProxyMux.proxies { - if p.listener != nil { - p.listener.Close() - } - } - - gwConfig := s.Gw.GetConfig() - - s.Gw.DefaultProxyMux.swap(&proxyMux{}, s.Gw) - if s.config.SeparateControlAPI { - gwConfig.ControlAPIPort = 0 - s.Gw.SetConfig(gwConfig) - } - - // if jsvm enabled we need to unmount to prevent high memory consumption - if s.Gw.GetConfig().EnableJSVM { - s.Gw.GlobalEventsJSVM.VM = nil - } - - ctxShutDown, cancel := context.WithTimeout(context.Background(), 5*time.Second) - defer cancel() - - err := s.HttpHandler.Shutdown(ctxShutDown) - if err != nil { - log.WithError(err).Error("shutting down the http handler") - } else { - log.Info("server exited properly") - } - - s.Gw.Analytics.Stop() - s.Gw.ReloadTestCase.StopTicker() - s.Gw.GlobalHostChecker.StopPoller() - s.Gw.NewRelicApplication.Shutdown(5 * time.Second) - - err = s.RemoveApis() - if err != nil { - log.Error("could not remove apis") - } - - s.Gw.cacheClose() -} - // RemoveApis clean all the apis from a living gw func (s *Test) RemoveApis() error { s.Gw.apisMu.Lock()