From 33304b62ed3857a97f5274d42a41951d2216e149 Mon Sep 17 00:00:00 2001 From: Mile Druzijanic <153705375+miledxz@users.noreply.github.com> Date: Thu, 29 Aug 2024 23:05:44 +0200 Subject: [PATCH] Test/add runtime manager tests (#2175) --------- Co-authored-by: Mile Druzijanic <153705375+zedGGs@users.noreply.github.com> Co-authored-by: Kate Osborn <50597707+kate-osborn@users.noreply.github.com> Co-authored-by: Saylor Berman --- internal/mode/static/manager.go | 11 +- .../mode/static/metrics/collectors/nginx.go | 10 +- internal/mode/static/nginx/runtime/manager.go | 91 ++++-- .../mode/static/nginx/runtime/manager_test.go | 225 ++++++++++++++- .../runtimefakes/fake_metrics_collector.go | 137 +++++++++ .../fake_nginx_config_verifier.go | 269 +++++++++++++++++ .../runtimefakes/fake_nginx_plus_client.go | 204 +++++++++++++ .../runtimefakes/fake_process_handler.go | 273 ++++++++++++++++++ .../runtimefakes/fake_verify_client.go | 269 +++++++++++++++++ internal/mode/static/nginx/runtime/verify.go | 42 ++- .../mode/static/nginx/runtime/verify_test.go | 8 +- 11 files changed, 1481 insertions(+), 58 deletions(-) create mode 100644 internal/mode/static/nginx/runtime/runtimefakes/fake_metrics_collector.go create mode 100644 internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_config_verifier.go create mode 100644 internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_plus_client.go create mode 100644 internal/mode/static/nginx/runtime/runtimefakes/fake_process_handler.go create mode 100644 internal/mode/static/nginx/runtime/runtimefakes/fake_verify_client.go diff --git a/internal/mode/static/manager.go b/internal/mode/static/manager.go index 7f58febaf9..9663f215cf 100644 --- a/internal/mode/static/manager.go +++ b/internal/mode/static/manager.go @@ -4,10 +4,10 @@ import ( "context" "errors" "fmt" + "os" "time" "github.com/go-logr/logr" - ngxclient "github.com/nginxinc/nginx-plus-go-client/client" tel "github.com/nginxinc/telemetry-exporter/pkg/telemetry" "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" @@ -146,8 +146,10 @@ func StartManager(cfg config.Config) error { return fmt.Errorf("cannot clear NGINX configuration folders: %w", err) } + processHandler := ngxruntime.NewProcessHandlerImpl(os.ReadFile, os.Stat) + // Ensure NGINX is running before registering metrics & starting the manager. - if err := ngxruntime.EnsureNginxRunning(ctx); err != nil { + if _, err := processHandler.FindMainProcess(ctx, ngxruntime.PidFileTimeout); err != nil { return fmt.Errorf("NGINX is not running: %w", err) } @@ -156,8 +158,9 @@ func StartManager(cfg config.Config) error { handlerCollector handlerMetricsCollector = collectors.NewControllerNoopCollector() ) - var ngxPlusClient *ngxclient.NginxClient + var ngxPlusClient ngxruntime.NginxPlusClient var usageSecret *usage.Secret + if cfg.Plus { ngxPlusClient, err = ngxruntime.CreatePlusClient() if err != nil { @@ -223,6 +226,8 @@ func StartManager(cfg config.Config) error { ngxPlusClient, ngxruntimeCollector, cfg.Logger.WithName("nginxRuntimeManager"), + processHandler, + ngxruntime.NewVerifyClient(ngxruntime.NginxReloadTimeout), ), statusUpdater: groupStatusUpdater, eventRecorder: recorder, diff --git a/internal/mode/static/metrics/collectors/nginx.go b/internal/mode/static/metrics/collectors/nginx.go index 28cbc635d3..f8ce60b26a 100644 --- a/internal/mode/static/metrics/collectors/nginx.go +++ b/internal/mode/static/metrics/collectors/nginx.go @@ -1,6 +1,8 @@ package collectors import ( + "fmt" + "github.com/go-kit/log" "github.com/nginxinc/nginx-plus-go-client/client" prometheusClient "github.com/nginxinc/nginx-prometheus-exporter/client" @@ -26,12 +28,16 @@ func NewNginxMetricsCollector(constLabels map[string]string, logger log.Logger) // NewNginxPlusMetricsCollector creates an NginxCollector which fetches stats from NGINX Plus API over a unix socket. func NewNginxPlusMetricsCollector( - plusClient *client.NginxClient, + plusClient runtime.NginxPlusClient, constLabels map[string]string, logger log.Logger, ) (prometheus.Collector, error) { + nc, ok := plusClient.(*client.NginxClient) + if !ok { + panic(fmt.Sprintf("expected *client.NginxClient, got %T", plusClient)) + } collector := nginxCollector.NewNginxPlusCollector( - plusClient, + nc, metrics.Namespace, nginxCollector.VariableLabelNames{}, constLabels, diff --git a/internal/mode/static/nginx/runtime/manager.go b/internal/mode/static/nginx/runtime/manager.go index a79c74b42c..fd7bf9e3fc 100644 --- a/internal/mode/static/nginx/runtime/manager.go +++ b/internal/mode/static/nginx/runtime/manager.go @@ -19,18 +19,36 @@ import ( //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate const ( - pidFile = "/var/run/nginx/nginx.pid" - pidFileTimeout = 10000 * time.Millisecond - nginxReloadTimeout = 60000 * time.Millisecond + // PidFile specifies the location of the PID file for the Nginx process. + PidFile = "/var/run/nginx/nginx.pid" + // PidFileTimeout defines the timeout duration for accessing the PID file. + PidFileTimeout = 10000 * time.Millisecond + // NginxReloadTimeout sets the timeout duration for reloading the Nginx configuration. + NginxReloadTimeout = 60000 * time.Millisecond ) type ( - readFileFunc func(string) ([]byte, error) - checkFileFunc func(string) (fs.FileInfo, error) + ReadFileFunc func(string) ([]byte, error) + CheckFileFunc func(string) (fs.FileInfo, error) ) var childProcPathFmt = "/proc/%[1]v/task/%[1]v/children" +//counterfeiter:generate . NginxPlusClient + +type NginxPlusClient interface { + UpdateHTTPServers( + upstream string, + servers []ngxclient.UpstreamServer, + ) ( + added []ngxclient.UpstreamServer, + deleted []ngxclient.UpstreamServer, + updated []ngxclient.UpstreamServer, + err error, + ) + GetUpstreams() (*ngxclient.Upstreams, error) +} + //counterfeiter:generate . Manager // Manager manages the runtime of NGINX. @@ -48,6 +66,8 @@ type Manager interface { } // MetricsCollector is an interface for the metrics of the NGINX runtime manager. +// +//counterfeiter:generate . MetricsCollector type MetricsCollector interface { IncReloadCount() IncReloadErrors() @@ -56,21 +76,25 @@ type MetricsCollector interface { // ManagerImpl implements Manager. type ManagerImpl struct { - verifyClient *verifyClient + processHandler ProcessHandler metricsCollector MetricsCollector - ngxPlusClient *ngxclient.NginxClient + verifyClient nginxConfigVerifier + ngxPlusClient NginxPlusClient logger logr.Logger } // NewManagerImpl creates a new ManagerImpl. func NewManagerImpl( - ngxPlusClient *ngxclient.NginxClient, + ngxPlusClient NginxPlusClient, collector MetricsCollector, logger logr.Logger, + processHandler ProcessHandler, + verifyClient nginxConfigVerifier, ) *ManagerImpl { return &ManagerImpl{ - verifyClient: newVerifyClient(nginxReloadTimeout), + processHandler: processHandler, metricsCollector: collector, + verifyClient: verifyClient, ngxPlusClient: ngxPlusClient, logger: logger, } @@ -84,25 +108,25 @@ func (m *ManagerImpl) IsPlus() bool { func (m *ManagerImpl) Reload(ctx context.Context, configVersion int) error { start := time.Now() // We find the main NGINX PID on every reload because it will change if the NGINX container is restarted. - pid, err := findMainProcess(ctx, os.Stat, os.ReadFile, pidFileTimeout) + pid, err := m.processHandler.FindMainProcess(ctx, PidFileTimeout) if err != nil { return fmt.Errorf("failed to find NGINX main process: %w", err) } childProcFile := fmt.Sprintf(childProcPathFmt, pid) - previousChildProcesses, err := os.ReadFile(childProcFile) + previousChildProcesses, err := m.processHandler.ReadFile(childProcFile) if err != nil { return err } // send HUP signal to the NGINX main process reload configuration // See https://nginx.org/en/docs/control.html - if err := syscall.Kill(pid, syscall.SIGHUP); err != nil { + if err := m.processHandler.Kill(pid); err != nil { m.metricsCollector.IncReloadErrors() return fmt.Errorf("failed to send the HUP signal to NGINX main: %w", err) } - if err = m.verifyClient.waitForCorrectVersion( + if err = m.verifyClient.WaitForCorrectVersion( ctx, configVersion, childProcFile, @@ -153,18 +177,31 @@ func (m *ManagerImpl) GetUpstreams() (ngxclient.Upstreams, error) { return *upstreams, nil } -// EnsureNginxRunning ensures NGINX is running by locating the main process. -func EnsureNginxRunning(ctx context.Context) error { - if _, err := findMainProcess(ctx, os.Stat, os.ReadFile, pidFileTimeout); err != nil { - return fmt.Errorf("failed to find NGINX main process: %w", err) +//counterfeiter:generate . ProcessHandler + +type ProcessHandler interface { + FindMainProcess( + ctx context.Context, + timeout time.Duration, + ) (int, error) + ReadFile(file string) ([]byte, error) + Kill(pid int) error +} + +type ProcessHandlerImpl struct { + readFile ReadFileFunc + checkFile CheckFileFunc +} + +func NewProcessHandlerImpl(readFile ReadFileFunc, checkFile CheckFileFunc) *ProcessHandlerImpl { + return &ProcessHandlerImpl{ + readFile: readFile, + checkFile: checkFile, } - return nil } -func findMainProcess( +func (p *ProcessHandlerImpl) FindMainProcess( ctx context.Context, - checkFile checkFileFunc, - readFile readFileFunc, timeout time.Duration, ) (int, error) { ctx, cancel := context.WithTimeout(ctx, timeout) @@ -175,7 +212,7 @@ func findMainProcess( 500*time.Millisecond, true, /* poll immediately */ func(_ context.Context) (bool, error) { - _, err := checkFile(pidFile) + _, err := p.checkFile(PidFile) if err == nil { return true, nil } @@ -188,7 +225,7 @@ func findMainProcess( return 0, err } - content, err := readFile(pidFile) + content, err := p.readFile(PidFile) if err != nil { return 0, err } @@ -200,3 +237,11 @@ func findMainProcess( return pid, nil } + +func (p *ProcessHandlerImpl) ReadFile(file string) ([]byte, error) { + return p.readFile(file) +} + +func (p *ProcessHandlerImpl) Kill(pid int) error { + return syscall.Kill(pid, syscall.SIGHUP) +} diff --git a/internal/mode/static/nginx/runtime/manager_test.go b/internal/mode/static/nginx/runtime/manager_test.go index 323bb514a5..7b3c30af15 100644 --- a/internal/mode/static/nginx/runtime/manager_test.go +++ b/internal/mode/static/nginx/runtime/manager_test.go @@ -1,32 +1,231 @@ -package runtime +package runtime_test import ( "context" "errors" + "fmt" "io/fs" "testing" "time" - "github.com/go-logr/logr" ngxclient "github.com/nginxinc/nginx-plus-go-client/client" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime" + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime/runtimefakes" ) var _ = Describe("NGINX Runtime Manager", func() { It("returns whether or not we're using NGINX Plus", func() { - mgr := NewManagerImpl(nil, nil, logr.New(GinkgoLogr.GetSink())) + mgr := runtime.NewManagerImpl(nil, nil, zap.New(), nil, nil) Expect(mgr.IsPlus()).To(BeFalse()) - mgr = NewManagerImpl(&ngxclient.NginxClient{}, nil, logr.New(GinkgoLogr.GetSink())) + mgr = runtime.NewManagerImpl(&ngxclient.NginxClient{}, nil, zap.New(), nil, nil) Expect(mgr.IsPlus()).To(BeTrue()) }) + + var ( + err error + manager runtime.Manager + upstreamServers []ngxclient.UpstreamServer + ngxPlusClient *runtimefakes.FakeNginxPlusClient + process *runtimefakes.FakeProcessHandler + + metrics *runtimefakes.FakeMetricsCollector + verifyClient *runtimefakes.FakeVerifyClient + ) + + BeforeEach(func() { + upstreamServers = []ngxclient.UpstreamServer{ + {}, + } + }) + + Context("Reload", func() { + BeforeEach(func() { + ngxPlusClient = &runtimefakes.FakeNginxPlusClient{} + process = &runtimefakes.FakeProcessHandler{} + metrics = &runtimefakes.FakeMetricsCollector{} + verifyClient = &runtimefakes.FakeVerifyClient{} + manager = runtime.NewManagerImpl(ngxPlusClient, metrics, zap.New(), process, verifyClient) + }) + + It("Is successful", func() { + Expect(manager.Reload(context.Background(), 1)).To(Succeed()) + + Expect(process.FindMainProcessCallCount()).To(Equal(1)) + Expect(process.ReadFileCallCount()).To(Equal(1)) + Expect(process.KillCallCount()).To(Equal(1)) + Expect(metrics.IncReloadCountCallCount()).To(Equal(1)) + Expect(verifyClient.WaitForCorrectVersionCallCount()).To(Equal(1)) + Expect(metrics.ObserveLastReloadTimeCallCount()).To(Equal(1)) + Expect(metrics.IncReloadErrorsCallCount()).To(Equal(0)) + }) + + It("Fails to find the main process", func() { + process.FindMainProcessReturns(0, fmt.Errorf("failed to find process")) + + err := manager.Reload(context.Background(), 1) + + Expect(err).To(MatchError("failed to find NGINX main process: failed to find process")) + Expect(process.ReadFileCallCount()).To(Equal(0)) + Expect(process.KillCallCount()).To(Equal(0)) + Expect(verifyClient.WaitForCorrectVersionCallCount()).To(Equal(0)) + }) + + It("Fails to read file", func() { + process.FindMainProcessReturns(1234, nil) + process.ReadFileReturns(nil, fmt.Errorf("failed to read file")) + + err := manager.Reload(context.Background(), 1) + + Expect(err).To(MatchError("failed to read file")) + Expect(process.KillCallCount()).To(Equal(0)) + Expect(verifyClient.WaitForCorrectVersionCallCount()).To(Equal(0)) + }) + + It("Fails to send kill signal", func() { + process.FindMainProcessReturns(1234, nil) + process.ReadFileReturns([]byte("child1\nchild2"), nil) + process.KillReturns(fmt.Errorf("failed to send kill signal")) + + err := manager.Reload(context.Background(), 1) + + Expect(err).To(MatchError("failed to send the HUP signal to NGINX main: failed to send kill signal")) + Expect(metrics.IncReloadErrorsCallCount()).To(Equal(1)) + Expect(verifyClient.WaitForCorrectVersionCallCount()).To(Equal(0)) + }) + + It("times out waiting for correct version", func() { + process.FindMainProcessReturns(1234, nil) + process.ReadFileReturns([]byte("child1\nchild2"), nil) + process.KillReturns(nil) + verifyClient.WaitForCorrectVersionReturns(fmt.Errorf("timeout waiting for correct version")) + + err := manager.Reload(context.Background(), 1) + + Expect(err).To(MatchError("timeout waiting for correct version")) + Expect(metrics.IncReloadErrorsCallCount()).To(Equal(1)) + }) + + When("MetricsCollector is nil", func() { + It("panics", func() { + metrics = nil + manager = runtime.NewManagerImpl(ngxPlusClient, metrics, zap.New(), process, verifyClient) + + reload := func() { + err = manager.Reload(context.Background(), 0) + } + + Expect(reload).To(Panic()) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + When("VerifyClient is nil", func() { + It("panics", func() { + metrics = &runtimefakes.FakeMetricsCollector{} + verifyClient = nil + manager = runtime.NewManagerImpl(ngxPlusClient, metrics, zap.New(), process, verifyClient) + + reload := func() { + err = manager.Reload(context.Background(), 0) + } + + Expect(reload).To(Panic()) + Expect(err).ToNot(HaveOccurred()) + }) + }) + }) + + When("running NGINX plus", func() { + BeforeEach(func() { + ngxPlusClient = &runtimefakes.FakeNginxPlusClient{} + manager = runtime.NewManagerImpl(ngxPlusClient, nil, zap.New(), nil, nil) + }) + + It("successfully updates HTTP server upstream", func() { + Expect(manager.UpdateHTTPServers("test", upstreamServers)).To(Succeed()) + }) + + It("returns no upstreams from NGINX Plus API when upstreams are nil", func() { + upstreams, err := manager.GetUpstreams() + + Expect(err).To(HaveOccurred()) + Expect(upstreams).To(BeEmpty()) + }) + + It("successfully returns server upstreams", func() { + expUpstreams := ngxclient.Upstreams{ + "upstream1": { + Zone: "zone1", + Peers: []ngxclient.Peer{ + {ID: 1, Name: "peer1-name"}, + }, + Queue: ngxclient.Queue{Size: 10}, + Zombies: 2, + }, + "upstream2": { + Zone: "zone2", + Peers: []ngxclient.Peer{ + {ID: 2, Name: "peer2-name"}, + }, + Queue: ngxclient.Queue{Size: 20}, + Zombies: 1, + }, + } + + ngxPlusClient.GetUpstreamsReturns(&expUpstreams, nil) + + upstreams, err := manager.GetUpstreams() + + Expect(err).NotTo(HaveOccurred()) + Expect(expUpstreams).To(Equal(upstreams)) + }) + + It("returns an error when GetUpstreams fails", func() { + ngxPlusClient.GetUpstreamsReturns(nil, errors.New("failed to get upstreams")) + + upstreams, err := manager.GetUpstreams() + + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError("failed to get upstreams")) + Expect(upstreams).To(BeNil()) + }) + }) + + When("not running NGINX plus", func() { + BeforeEach(func() { + ngxPlusClient = nil + manager = runtime.NewManagerImpl(ngxPlusClient, nil, zap.New(), nil, nil) + }) + + It("should panic when updating HTTP upstream servers", func() { + updateServers := func() { + err = manager.UpdateHTTPServers("test", upstreamServers) + } + + Expect(updateServers).To(Panic()) + Expect(err).ToNot(HaveOccurred()) + }) + + It("should panic when fetching HTTP upstream servers", func() { + upstreams := func() { + _, err = manager.GetUpstreams() + } + + Expect(upstreams).To(Panic()) + Expect(err).ToNot(HaveOccurred()) + }) + }) }) func TestFindMainProcess(t *testing.T) { - readFileFuncGen := func(content []byte) readFileFunc { + readFileFuncGen := func(content []byte) runtime.ReadFileFunc { return func(name string) ([]byte, error) { - if name != pidFile { + if name != runtime.PidFile { return nil, errors.New("error") } return content, nil @@ -36,9 +235,9 @@ func TestFindMainProcess(t *testing.T) { return nil, errors.New("error") } - checkFileFuncGen := func(content fs.FileInfo) checkFileFunc { + checkFileFuncGen := func(content fs.FileInfo) runtime.CheckFileFunc { return func(name string) (fs.FileInfo, error) { - if name != pidFile { + if name != runtime.PidFile { return nil, errors.New("error") } return content, nil @@ -54,8 +253,8 @@ func TestFindMainProcess(t *testing.T) { tests := []struct { ctx context.Context - readFile readFileFunc - checkFile checkFileFunc + readFile runtime.ReadFileFunc + checkFile runtime.CheckFileFunc name string expected int expectError bool @@ -113,8 +312,10 @@ func TestFindMainProcess(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { g := NewWithT(t) - - result, err := findMainProcess(test.ctx, test.checkFile, test.readFile, 2*time.Millisecond) + p := runtime.NewProcessHandlerImpl( + test.readFile, + test.checkFile) + result, err := p.FindMainProcess(test.ctx, 2*time.Millisecond) if test.expectError { g.Expect(err).To(HaveOccurred()) diff --git a/internal/mode/static/nginx/runtime/runtimefakes/fake_metrics_collector.go b/internal/mode/static/nginx/runtime/runtimefakes/fake_metrics_collector.go new file mode 100644 index 0000000000..4562c2c5c2 --- /dev/null +++ b/internal/mode/static/nginx/runtime/runtimefakes/fake_metrics_collector.go @@ -0,0 +1,137 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package runtimefakes + +import ( + "sync" + "time" + + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime" +) + +type FakeMetricsCollector struct { + IncReloadCountStub func() + incReloadCountMutex sync.RWMutex + incReloadCountArgsForCall []struct { + } + IncReloadErrorsStub func() + incReloadErrorsMutex sync.RWMutex + incReloadErrorsArgsForCall []struct { + } + ObserveLastReloadTimeStub func(time.Duration) + observeLastReloadTimeMutex sync.RWMutex + observeLastReloadTimeArgsForCall []struct { + arg1 time.Duration + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeMetricsCollector) IncReloadCount() { + fake.incReloadCountMutex.Lock() + fake.incReloadCountArgsForCall = append(fake.incReloadCountArgsForCall, struct { + }{}) + stub := fake.IncReloadCountStub + fake.recordInvocation("IncReloadCount", []interface{}{}) + fake.incReloadCountMutex.Unlock() + if stub != nil { + fake.IncReloadCountStub() + } +} + +func (fake *FakeMetricsCollector) IncReloadCountCallCount() int { + fake.incReloadCountMutex.RLock() + defer fake.incReloadCountMutex.RUnlock() + return len(fake.incReloadCountArgsForCall) +} + +func (fake *FakeMetricsCollector) IncReloadCountCalls(stub func()) { + fake.incReloadCountMutex.Lock() + defer fake.incReloadCountMutex.Unlock() + fake.IncReloadCountStub = stub +} + +func (fake *FakeMetricsCollector) IncReloadErrors() { + fake.incReloadErrorsMutex.Lock() + fake.incReloadErrorsArgsForCall = append(fake.incReloadErrorsArgsForCall, struct { + }{}) + stub := fake.IncReloadErrorsStub + fake.recordInvocation("IncReloadErrors", []interface{}{}) + fake.incReloadErrorsMutex.Unlock() + if stub != nil { + fake.IncReloadErrorsStub() + } +} + +func (fake *FakeMetricsCollector) IncReloadErrorsCallCount() int { + fake.incReloadErrorsMutex.RLock() + defer fake.incReloadErrorsMutex.RUnlock() + return len(fake.incReloadErrorsArgsForCall) +} + +func (fake *FakeMetricsCollector) IncReloadErrorsCalls(stub func()) { + fake.incReloadErrorsMutex.Lock() + defer fake.incReloadErrorsMutex.Unlock() + fake.IncReloadErrorsStub = stub +} + +func (fake *FakeMetricsCollector) ObserveLastReloadTime(arg1 time.Duration) { + fake.observeLastReloadTimeMutex.Lock() + fake.observeLastReloadTimeArgsForCall = append(fake.observeLastReloadTimeArgsForCall, struct { + arg1 time.Duration + }{arg1}) + stub := fake.ObserveLastReloadTimeStub + fake.recordInvocation("ObserveLastReloadTime", []interface{}{arg1}) + fake.observeLastReloadTimeMutex.Unlock() + if stub != nil { + fake.ObserveLastReloadTimeStub(arg1) + } +} + +func (fake *FakeMetricsCollector) ObserveLastReloadTimeCallCount() int { + fake.observeLastReloadTimeMutex.RLock() + defer fake.observeLastReloadTimeMutex.RUnlock() + return len(fake.observeLastReloadTimeArgsForCall) +} + +func (fake *FakeMetricsCollector) ObserveLastReloadTimeCalls(stub func(time.Duration)) { + fake.observeLastReloadTimeMutex.Lock() + defer fake.observeLastReloadTimeMutex.Unlock() + fake.ObserveLastReloadTimeStub = stub +} + +func (fake *FakeMetricsCollector) ObserveLastReloadTimeArgsForCall(i int) time.Duration { + fake.observeLastReloadTimeMutex.RLock() + defer fake.observeLastReloadTimeMutex.RUnlock() + argsForCall := fake.observeLastReloadTimeArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeMetricsCollector) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.incReloadCountMutex.RLock() + defer fake.incReloadCountMutex.RUnlock() + fake.incReloadErrorsMutex.RLock() + defer fake.incReloadErrorsMutex.RUnlock() + fake.observeLastReloadTimeMutex.RLock() + defer fake.observeLastReloadTimeMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeMetricsCollector) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ runtime.MetricsCollector = new(FakeMetricsCollector) diff --git a/internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_config_verifier.go b/internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_config_verifier.go new file mode 100644 index 0000000000..23c5c67348 --- /dev/null +++ b/internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_config_verifier.go @@ -0,0 +1,269 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package runtimefakes + +import ( + "context" + "sync" + + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime" +) + +type FakeNginxConfigVerifier struct { + EnsureConfigVersionStub func(context.Context, int) error + ensureConfigVersionMutex sync.RWMutex + ensureConfigVersionArgsForCall []struct { + arg1 context.Context + arg2 int + } + ensureConfigVersionReturns struct { + result1 error + } + ensureConfigVersionReturnsOnCall map[int]struct { + result1 error + } + GetConfigVersionStub func() (int, error) + getConfigVersionMutex sync.RWMutex + getConfigVersionArgsForCall []struct { + } + getConfigVersionReturns struct { + result1 int + result2 error + } + getConfigVersionReturnsOnCall map[int]struct { + result1 int + result2 error + } + WaitForCorrectVersionStub func(context.Context, int, string, []byte, runtime.ReadFileFunc) error + waitForCorrectVersionMutex sync.RWMutex + waitForCorrectVersionArgsForCall []struct { + arg1 context.Context + arg2 int + arg3 string + arg4 []byte + arg5 runtime.ReadFileFunc + } + waitForCorrectVersionReturns struct { + result1 error + } + waitForCorrectVersionReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeNginxConfigVerifier) EnsureConfigVersion(arg1 context.Context, arg2 int) error { + fake.ensureConfigVersionMutex.Lock() + ret, specificReturn := fake.ensureConfigVersionReturnsOnCall[len(fake.ensureConfigVersionArgsForCall)] + fake.ensureConfigVersionArgsForCall = append(fake.ensureConfigVersionArgsForCall, struct { + arg1 context.Context + arg2 int + }{arg1, arg2}) + stub := fake.EnsureConfigVersionStub + fakeReturns := fake.ensureConfigVersionReturns + fake.recordInvocation("EnsureConfigVersion", []interface{}{arg1, arg2}) + fake.ensureConfigVersionMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeNginxConfigVerifier) EnsureConfigVersionCallCount() int { + fake.ensureConfigVersionMutex.RLock() + defer fake.ensureConfigVersionMutex.RUnlock() + return len(fake.ensureConfigVersionArgsForCall) +} + +func (fake *FakeNginxConfigVerifier) EnsureConfigVersionCalls(stub func(context.Context, int) error) { + fake.ensureConfigVersionMutex.Lock() + defer fake.ensureConfigVersionMutex.Unlock() + fake.EnsureConfigVersionStub = stub +} + +func (fake *FakeNginxConfigVerifier) EnsureConfigVersionArgsForCall(i int) (context.Context, int) { + fake.ensureConfigVersionMutex.RLock() + defer fake.ensureConfigVersionMutex.RUnlock() + argsForCall := fake.ensureConfigVersionArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeNginxConfigVerifier) EnsureConfigVersionReturns(result1 error) { + fake.ensureConfigVersionMutex.Lock() + defer fake.ensureConfigVersionMutex.Unlock() + fake.EnsureConfigVersionStub = nil + fake.ensureConfigVersionReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeNginxConfigVerifier) EnsureConfigVersionReturnsOnCall(i int, result1 error) { + fake.ensureConfigVersionMutex.Lock() + defer fake.ensureConfigVersionMutex.Unlock() + fake.EnsureConfigVersionStub = nil + if fake.ensureConfigVersionReturnsOnCall == nil { + fake.ensureConfigVersionReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.ensureConfigVersionReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeNginxConfigVerifier) GetConfigVersion() (int, error) { + fake.getConfigVersionMutex.Lock() + ret, specificReturn := fake.getConfigVersionReturnsOnCall[len(fake.getConfigVersionArgsForCall)] + fake.getConfigVersionArgsForCall = append(fake.getConfigVersionArgsForCall, struct { + }{}) + stub := fake.GetConfigVersionStub + fakeReturns := fake.getConfigVersionReturns + fake.recordInvocation("GetConfigVersion", []interface{}{}) + fake.getConfigVersionMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeNginxConfigVerifier) GetConfigVersionCallCount() int { + fake.getConfigVersionMutex.RLock() + defer fake.getConfigVersionMutex.RUnlock() + return len(fake.getConfigVersionArgsForCall) +} + +func (fake *FakeNginxConfigVerifier) GetConfigVersionCalls(stub func() (int, error)) { + fake.getConfigVersionMutex.Lock() + defer fake.getConfigVersionMutex.Unlock() + fake.GetConfigVersionStub = stub +} + +func (fake *FakeNginxConfigVerifier) GetConfigVersionReturns(result1 int, result2 error) { + fake.getConfigVersionMutex.Lock() + defer fake.getConfigVersionMutex.Unlock() + fake.GetConfigVersionStub = nil + fake.getConfigVersionReturns = struct { + result1 int + result2 error + }{result1, result2} +} + +func (fake *FakeNginxConfigVerifier) GetConfigVersionReturnsOnCall(i int, result1 int, result2 error) { + fake.getConfigVersionMutex.Lock() + defer fake.getConfigVersionMutex.Unlock() + fake.GetConfigVersionStub = nil + if fake.getConfigVersionReturnsOnCall == nil { + fake.getConfigVersionReturnsOnCall = make(map[int]struct { + result1 int + result2 error + }) + } + fake.getConfigVersionReturnsOnCall[i] = struct { + result1 int + result2 error + }{result1, result2} +} + +func (fake *FakeNginxConfigVerifier) WaitForCorrectVersion(arg1 context.Context, arg2 int, arg3 string, arg4 []byte, arg5 runtime.ReadFileFunc) error { + var arg4Copy []byte + if arg4 != nil { + arg4Copy = make([]byte, len(arg4)) + copy(arg4Copy, arg4) + } + fake.waitForCorrectVersionMutex.Lock() + ret, specificReturn := fake.waitForCorrectVersionReturnsOnCall[len(fake.waitForCorrectVersionArgsForCall)] + fake.waitForCorrectVersionArgsForCall = append(fake.waitForCorrectVersionArgsForCall, struct { + arg1 context.Context + arg2 int + arg3 string + arg4 []byte + arg5 runtime.ReadFileFunc + }{arg1, arg2, arg3, arg4Copy, arg5}) + stub := fake.WaitForCorrectVersionStub + fakeReturns := fake.waitForCorrectVersionReturns + fake.recordInvocation("WaitForCorrectVersion", []interface{}{arg1, arg2, arg3, arg4Copy, arg5}) + fake.waitForCorrectVersionMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4, arg5) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeNginxConfigVerifier) WaitForCorrectVersionCallCount() int { + fake.waitForCorrectVersionMutex.RLock() + defer fake.waitForCorrectVersionMutex.RUnlock() + return len(fake.waitForCorrectVersionArgsForCall) +} + +func (fake *FakeNginxConfigVerifier) WaitForCorrectVersionCalls(stub func(context.Context, int, string, []byte, runtime.ReadFileFunc) error) { + fake.waitForCorrectVersionMutex.Lock() + defer fake.waitForCorrectVersionMutex.Unlock() + fake.WaitForCorrectVersionStub = stub +} + +func (fake *FakeNginxConfigVerifier) WaitForCorrectVersionArgsForCall(i int) (context.Context, int, string, []byte, runtime.ReadFileFunc) { + fake.waitForCorrectVersionMutex.RLock() + defer fake.waitForCorrectVersionMutex.RUnlock() + argsForCall := fake.waitForCorrectVersionArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 +} + +func (fake *FakeNginxConfigVerifier) WaitForCorrectVersionReturns(result1 error) { + fake.waitForCorrectVersionMutex.Lock() + defer fake.waitForCorrectVersionMutex.Unlock() + fake.WaitForCorrectVersionStub = nil + fake.waitForCorrectVersionReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeNginxConfigVerifier) WaitForCorrectVersionReturnsOnCall(i int, result1 error) { + fake.waitForCorrectVersionMutex.Lock() + defer fake.waitForCorrectVersionMutex.Unlock() + fake.WaitForCorrectVersionStub = nil + if fake.waitForCorrectVersionReturnsOnCall == nil { + fake.waitForCorrectVersionReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.waitForCorrectVersionReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeNginxConfigVerifier) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.ensureConfigVersionMutex.RLock() + defer fake.ensureConfigVersionMutex.RUnlock() + fake.getConfigVersionMutex.RLock() + defer fake.getConfigVersionMutex.RUnlock() + fake.waitForCorrectVersionMutex.RLock() + defer fake.waitForCorrectVersionMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeNginxConfigVerifier) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} diff --git a/internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_plus_client.go b/internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_plus_client.go new file mode 100644 index 0000000000..3ea431d29b --- /dev/null +++ b/internal/mode/static/nginx/runtime/runtimefakes/fake_nginx_plus_client.go @@ -0,0 +1,204 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package runtimefakes + +import ( + "sync" + + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime" + "github.com/nginxinc/nginx-plus-go-client/client" +) + +type FakeNginxPlusClient struct { + GetUpstreamsStub func() (*client.Upstreams, error) + getUpstreamsMutex sync.RWMutex + getUpstreamsArgsForCall []struct { + } + getUpstreamsReturns struct { + result1 *client.Upstreams + result2 error + } + getUpstreamsReturnsOnCall map[int]struct { + result1 *client.Upstreams + result2 error + } + UpdateHTTPServersStub func(string, []client.UpstreamServer) ([]client.UpstreamServer, []client.UpstreamServer, []client.UpstreamServer, error) + updateHTTPServersMutex sync.RWMutex + updateHTTPServersArgsForCall []struct { + arg1 string + arg2 []client.UpstreamServer + } + updateHTTPServersReturns struct { + result1 []client.UpstreamServer + result2 []client.UpstreamServer + result3 []client.UpstreamServer + result4 error + } + updateHTTPServersReturnsOnCall map[int]struct { + result1 []client.UpstreamServer + result2 []client.UpstreamServer + result3 []client.UpstreamServer + result4 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeNginxPlusClient) GetUpstreams() (*client.Upstreams, error) { + fake.getUpstreamsMutex.Lock() + ret, specificReturn := fake.getUpstreamsReturnsOnCall[len(fake.getUpstreamsArgsForCall)] + fake.getUpstreamsArgsForCall = append(fake.getUpstreamsArgsForCall, struct { + }{}) + stub := fake.GetUpstreamsStub + fakeReturns := fake.getUpstreamsReturns + fake.recordInvocation("GetUpstreams", []interface{}{}) + fake.getUpstreamsMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeNginxPlusClient) GetUpstreamsCallCount() int { + fake.getUpstreamsMutex.RLock() + defer fake.getUpstreamsMutex.RUnlock() + return len(fake.getUpstreamsArgsForCall) +} + +func (fake *FakeNginxPlusClient) GetUpstreamsCalls(stub func() (*client.Upstreams, error)) { + fake.getUpstreamsMutex.Lock() + defer fake.getUpstreamsMutex.Unlock() + fake.GetUpstreamsStub = stub +} + +func (fake *FakeNginxPlusClient) GetUpstreamsReturns(result1 *client.Upstreams, result2 error) { + fake.getUpstreamsMutex.Lock() + defer fake.getUpstreamsMutex.Unlock() + fake.GetUpstreamsStub = nil + fake.getUpstreamsReturns = struct { + result1 *client.Upstreams + result2 error + }{result1, result2} +} + +func (fake *FakeNginxPlusClient) GetUpstreamsReturnsOnCall(i int, result1 *client.Upstreams, result2 error) { + fake.getUpstreamsMutex.Lock() + defer fake.getUpstreamsMutex.Unlock() + fake.GetUpstreamsStub = nil + if fake.getUpstreamsReturnsOnCall == nil { + fake.getUpstreamsReturnsOnCall = make(map[int]struct { + result1 *client.Upstreams + result2 error + }) + } + fake.getUpstreamsReturnsOnCall[i] = struct { + result1 *client.Upstreams + result2 error + }{result1, result2} +} + +func (fake *FakeNginxPlusClient) UpdateHTTPServers(arg1 string, arg2 []client.UpstreamServer) ([]client.UpstreamServer, []client.UpstreamServer, []client.UpstreamServer, error) { + var arg2Copy []client.UpstreamServer + if arg2 != nil { + arg2Copy = make([]client.UpstreamServer, len(arg2)) + copy(arg2Copy, arg2) + } + fake.updateHTTPServersMutex.Lock() + ret, specificReturn := fake.updateHTTPServersReturnsOnCall[len(fake.updateHTTPServersArgsForCall)] + fake.updateHTTPServersArgsForCall = append(fake.updateHTTPServersArgsForCall, struct { + arg1 string + arg2 []client.UpstreamServer + }{arg1, arg2Copy}) + stub := fake.UpdateHTTPServersStub + fakeReturns := fake.updateHTTPServersReturns + fake.recordInvocation("UpdateHTTPServers", []interface{}{arg1, arg2Copy}) + fake.updateHTTPServersMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2, ret.result3, ret.result4 + } + return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3, fakeReturns.result4 +} + +func (fake *FakeNginxPlusClient) UpdateHTTPServersCallCount() int { + fake.updateHTTPServersMutex.RLock() + defer fake.updateHTTPServersMutex.RUnlock() + return len(fake.updateHTTPServersArgsForCall) +} + +func (fake *FakeNginxPlusClient) UpdateHTTPServersCalls(stub func(string, []client.UpstreamServer) ([]client.UpstreamServer, []client.UpstreamServer, []client.UpstreamServer, error)) { + fake.updateHTTPServersMutex.Lock() + defer fake.updateHTTPServersMutex.Unlock() + fake.UpdateHTTPServersStub = stub +} + +func (fake *FakeNginxPlusClient) UpdateHTTPServersArgsForCall(i int) (string, []client.UpstreamServer) { + fake.updateHTTPServersMutex.RLock() + defer fake.updateHTTPServersMutex.RUnlock() + argsForCall := fake.updateHTTPServersArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeNginxPlusClient) UpdateHTTPServersReturns(result1 []client.UpstreamServer, result2 []client.UpstreamServer, result3 []client.UpstreamServer, result4 error) { + fake.updateHTTPServersMutex.Lock() + defer fake.updateHTTPServersMutex.Unlock() + fake.UpdateHTTPServersStub = nil + fake.updateHTTPServersReturns = struct { + result1 []client.UpstreamServer + result2 []client.UpstreamServer + result3 []client.UpstreamServer + result4 error + }{result1, result2, result3, result4} +} + +func (fake *FakeNginxPlusClient) UpdateHTTPServersReturnsOnCall(i int, result1 []client.UpstreamServer, result2 []client.UpstreamServer, result3 []client.UpstreamServer, result4 error) { + fake.updateHTTPServersMutex.Lock() + defer fake.updateHTTPServersMutex.Unlock() + fake.UpdateHTTPServersStub = nil + if fake.updateHTTPServersReturnsOnCall == nil { + fake.updateHTTPServersReturnsOnCall = make(map[int]struct { + result1 []client.UpstreamServer + result2 []client.UpstreamServer + result3 []client.UpstreamServer + result4 error + }) + } + fake.updateHTTPServersReturnsOnCall[i] = struct { + result1 []client.UpstreamServer + result2 []client.UpstreamServer + result3 []client.UpstreamServer + result4 error + }{result1, result2, result3, result4} +} + +func (fake *FakeNginxPlusClient) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.getUpstreamsMutex.RLock() + defer fake.getUpstreamsMutex.RUnlock() + fake.updateHTTPServersMutex.RLock() + defer fake.updateHTTPServersMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeNginxPlusClient) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ runtime.NginxPlusClient = new(FakeNginxPlusClient) diff --git a/internal/mode/static/nginx/runtime/runtimefakes/fake_process_handler.go b/internal/mode/static/nginx/runtime/runtimefakes/fake_process_handler.go new file mode 100644 index 0000000000..bae52e2fa7 --- /dev/null +++ b/internal/mode/static/nginx/runtime/runtimefakes/fake_process_handler.go @@ -0,0 +1,273 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package runtimefakes + +import ( + "context" + "sync" + "time" + + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime" +) + +type FakeProcessHandler struct { + FindMainProcessStub func(context.Context, time.Duration) (int, error) + findMainProcessMutex sync.RWMutex + findMainProcessArgsForCall []struct { + arg1 context.Context + arg2 time.Duration + } + findMainProcessReturns struct { + result1 int + result2 error + } + findMainProcessReturnsOnCall map[int]struct { + result1 int + result2 error + } + KillStub func(int) error + killMutex sync.RWMutex + killArgsForCall []struct { + arg1 int + } + killReturns struct { + result1 error + } + killReturnsOnCall map[int]struct { + result1 error + } + ReadFileStub func(string) ([]byte, error) + readFileMutex sync.RWMutex + readFileArgsForCall []struct { + arg1 string + } + readFileReturns struct { + result1 []byte + result2 error + } + readFileReturnsOnCall map[int]struct { + result1 []byte + result2 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeProcessHandler) FindMainProcess(arg1 context.Context, arg2 time.Duration) (int, error) { + fake.findMainProcessMutex.Lock() + ret, specificReturn := fake.findMainProcessReturnsOnCall[len(fake.findMainProcessArgsForCall)] + fake.findMainProcessArgsForCall = append(fake.findMainProcessArgsForCall, struct { + arg1 context.Context + arg2 time.Duration + }{arg1, arg2}) + stub := fake.FindMainProcessStub + fakeReturns := fake.findMainProcessReturns + fake.recordInvocation("FindMainProcess", []interface{}{arg1, arg2}) + fake.findMainProcessMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeProcessHandler) FindMainProcessCallCount() int { + fake.findMainProcessMutex.RLock() + defer fake.findMainProcessMutex.RUnlock() + return len(fake.findMainProcessArgsForCall) +} + +func (fake *FakeProcessHandler) FindMainProcessCalls(stub func(context.Context, time.Duration) (int, error)) { + fake.findMainProcessMutex.Lock() + defer fake.findMainProcessMutex.Unlock() + fake.FindMainProcessStub = stub +} + +func (fake *FakeProcessHandler) FindMainProcessArgsForCall(i int) (context.Context, time.Duration) { + fake.findMainProcessMutex.RLock() + defer fake.findMainProcessMutex.RUnlock() + argsForCall := fake.findMainProcessArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeProcessHandler) FindMainProcessReturns(result1 int, result2 error) { + fake.findMainProcessMutex.Lock() + defer fake.findMainProcessMutex.Unlock() + fake.FindMainProcessStub = nil + fake.findMainProcessReturns = struct { + result1 int + result2 error + }{result1, result2} +} + +func (fake *FakeProcessHandler) FindMainProcessReturnsOnCall(i int, result1 int, result2 error) { + fake.findMainProcessMutex.Lock() + defer fake.findMainProcessMutex.Unlock() + fake.FindMainProcessStub = nil + if fake.findMainProcessReturnsOnCall == nil { + fake.findMainProcessReturnsOnCall = make(map[int]struct { + result1 int + result2 error + }) + } + fake.findMainProcessReturnsOnCall[i] = struct { + result1 int + result2 error + }{result1, result2} +} + +func (fake *FakeProcessHandler) Kill(arg1 int) error { + fake.killMutex.Lock() + ret, specificReturn := fake.killReturnsOnCall[len(fake.killArgsForCall)] + fake.killArgsForCall = append(fake.killArgsForCall, struct { + arg1 int + }{arg1}) + stub := fake.KillStub + fakeReturns := fake.killReturns + fake.recordInvocation("Kill", []interface{}{arg1}) + fake.killMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeProcessHandler) KillCallCount() int { + fake.killMutex.RLock() + defer fake.killMutex.RUnlock() + return len(fake.killArgsForCall) +} + +func (fake *FakeProcessHandler) KillCalls(stub func(int) error) { + fake.killMutex.Lock() + defer fake.killMutex.Unlock() + fake.KillStub = stub +} + +func (fake *FakeProcessHandler) KillArgsForCall(i int) int { + fake.killMutex.RLock() + defer fake.killMutex.RUnlock() + argsForCall := fake.killArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeProcessHandler) KillReturns(result1 error) { + fake.killMutex.Lock() + defer fake.killMutex.Unlock() + fake.KillStub = nil + fake.killReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeProcessHandler) KillReturnsOnCall(i int, result1 error) { + fake.killMutex.Lock() + defer fake.killMutex.Unlock() + fake.KillStub = nil + if fake.killReturnsOnCall == nil { + fake.killReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.killReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeProcessHandler) ReadFile(arg1 string) ([]byte, error) { + fake.readFileMutex.Lock() + ret, specificReturn := fake.readFileReturnsOnCall[len(fake.readFileArgsForCall)] + fake.readFileArgsForCall = append(fake.readFileArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.ReadFileStub + fakeReturns := fake.readFileReturns + fake.recordInvocation("ReadFile", []interface{}{arg1}) + fake.readFileMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeProcessHandler) ReadFileCallCount() int { + fake.readFileMutex.RLock() + defer fake.readFileMutex.RUnlock() + return len(fake.readFileArgsForCall) +} + +func (fake *FakeProcessHandler) ReadFileCalls(stub func(string) ([]byte, error)) { + fake.readFileMutex.Lock() + defer fake.readFileMutex.Unlock() + fake.ReadFileStub = stub +} + +func (fake *FakeProcessHandler) ReadFileArgsForCall(i int) string { + fake.readFileMutex.RLock() + defer fake.readFileMutex.RUnlock() + argsForCall := fake.readFileArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeProcessHandler) ReadFileReturns(result1 []byte, result2 error) { + fake.readFileMutex.Lock() + defer fake.readFileMutex.Unlock() + fake.ReadFileStub = nil + fake.readFileReturns = struct { + result1 []byte + result2 error + }{result1, result2} +} + +func (fake *FakeProcessHandler) ReadFileReturnsOnCall(i int, result1 []byte, result2 error) { + fake.readFileMutex.Lock() + defer fake.readFileMutex.Unlock() + fake.ReadFileStub = nil + if fake.readFileReturnsOnCall == nil { + fake.readFileReturnsOnCall = make(map[int]struct { + result1 []byte + result2 error + }) + } + fake.readFileReturnsOnCall[i] = struct { + result1 []byte + result2 error + }{result1, result2} +} + +func (fake *FakeProcessHandler) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.findMainProcessMutex.RLock() + defer fake.findMainProcessMutex.RUnlock() + fake.killMutex.RLock() + defer fake.killMutex.RUnlock() + fake.readFileMutex.RLock() + defer fake.readFileMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeProcessHandler) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} + +var _ runtime.ProcessHandler = new(FakeProcessHandler) diff --git a/internal/mode/static/nginx/runtime/runtimefakes/fake_verify_client.go b/internal/mode/static/nginx/runtime/runtimefakes/fake_verify_client.go new file mode 100644 index 0000000000..13c5f78224 --- /dev/null +++ b/internal/mode/static/nginx/runtime/runtimefakes/fake_verify_client.go @@ -0,0 +1,269 @@ +// Code generated by counterfeiter. DO NOT EDIT. +package runtimefakes + +import ( + "context" + "sync" + + "github.com/nginxinc/nginx-gateway-fabric/internal/mode/static/nginx/runtime" +) + +type FakeVerifyClient struct { + EnsureConfigVersionStub func(context.Context, int) error + ensureConfigVersionMutex sync.RWMutex + ensureConfigVersionArgsForCall []struct { + arg1 context.Context + arg2 int + } + ensureConfigVersionReturns struct { + result1 error + } + ensureConfigVersionReturnsOnCall map[int]struct { + result1 error + } + GetConfigVersionStub func() (int, error) + getConfigVersionMutex sync.RWMutex + getConfigVersionArgsForCall []struct { + } + getConfigVersionReturns struct { + result1 int + result2 error + } + getConfigVersionReturnsOnCall map[int]struct { + result1 int + result2 error + } + WaitForCorrectVersionStub func(context.Context, int, string, []byte, runtime.ReadFileFunc) error + waitForCorrectVersionMutex sync.RWMutex + waitForCorrectVersionArgsForCall []struct { + arg1 context.Context + arg2 int + arg3 string + arg4 []byte + arg5 runtime.ReadFileFunc + } + waitForCorrectVersionReturns struct { + result1 error + } + waitForCorrectVersionReturnsOnCall map[int]struct { + result1 error + } + invocations map[string][][]interface{} + invocationsMutex sync.RWMutex +} + +func (fake *FakeVerifyClient) EnsureConfigVersion(arg1 context.Context, arg2 int) error { + fake.ensureConfigVersionMutex.Lock() + ret, specificReturn := fake.ensureConfigVersionReturnsOnCall[len(fake.ensureConfigVersionArgsForCall)] + fake.ensureConfigVersionArgsForCall = append(fake.ensureConfigVersionArgsForCall, struct { + arg1 context.Context + arg2 int + }{arg1, arg2}) + stub := fake.EnsureConfigVersionStub + fakeReturns := fake.ensureConfigVersionReturns + fake.recordInvocation("EnsureConfigVersion", []interface{}{arg1, arg2}) + fake.ensureConfigVersionMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeVerifyClient) EnsureConfigVersionCallCount() int { + fake.ensureConfigVersionMutex.RLock() + defer fake.ensureConfigVersionMutex.RUnlock() + return len(fake.ensureConfigVersionArgsForCall) +} + +func (fake *FakeVerifyClient) EnsureConfigVersionCalls(stub func(context.Context, int) error) { + fake.ensureConfigVersionMutex.Lock() + defer fake.ensureConfigVersionMutex.Unlock() + fake.EnsureConfigVersionStub = stub +} + +func (fake *FakeVerifyClient) EnsureConfigVersionArgsForCall(i int) (context.Context, int) { + fake.ensureConfigVersionMutex.RLock() + defer fake.ensureConfigVersionMutex.RUnlock() + argsForCall := fake.ensureConfigVersionArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeVerifyClient) EnsureConfigVersionReturns(result1 error) { + fake.ensureConfigVersionMutex.Lock() + defer fake.ensureConfigVersionMutex.Unlock() + fake.EnsureConfigVersionStub = nil + fake.ensureConfigVersionReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeVerifyClient) EnsureConfigVersionReturnsOnCall(i int, result1 error) { + fake.ensureConfigVersionMutex.Lock() + defer fake.ensureConfigVersionMutex.Unlock() + fake.EnsureConfigVersionStub = nil + if fake.ensureConfigVersionReturnsOnCall == nil { + fake.ensureConfigVersionReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.ensureConfigVersionReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeVerifyClient) GetConfigVersion() (int, error) { + fake.getConfigVersionMutex.Lock() + ret, specificReturn := fake.getConfigVersionReturnsOnCall[len(fake.getConfigVersionArgsForCall)] + fake.getConfigVersionArgsForCall = append(fake.getConfigVersionArgsForCall, struct { + }{}) + stub := fake.GetConfigVersionStub + fakeReturns := fake.getConfigVersionReturns + fake.recordInvocation("GetConfigVersion", []interface{}{}) + fake.getConfigVersionMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeVerifyClient) GetConfigVersionCallCount() int { + fake.getConfigVersionMutex.RLock() + defer fake.getConfigVersionMutex.RUnlock() + return len(fake.getConfigVersionArgsForCall) +} + +func (fake *FakeVerifyClient) GetConfigVersionCalls(stub func() (int, error)) { + fake.getConfigVersionMutex.Lock() + defer fake.getConfigVersionMutex.Unlock() + fake.GetConfigVersionStub = stub +} + +func (fake *FakeVerifyClient) GetConfigVersionReturns(result1 int, result2 error) { + fake.getConfigVersionMutex.Lock() + defer fake.getConfigVersionMutex.Unlock() + fake.GetConfigVersionStub = nil + fake.getConfigVersionReturns = struct { + result1 int + result2 error + }{result1, result2} +} + +func (fake *FakeVerifyClient) GetConfigVersionReturnsOnCall(i int, result1 int, result2 error) { + fake.getConfigVersionMutex.Lock() + defer fake.getConfigVersionMutex.Unlock() + fake.GetConfigVersionStub = nil + if fake.getConfigVersionReturnsOnCall == nil { + fake.getConfigVersionReturnsOnCall = make(map[int]struct { + result1 int + result2 error + }) + } + fake.getConfigVersionReturnsOnCall[i] = struct { + result1 int + result2 error + }{result1, result2} +} + +func (fake *FakeVerifyClient) WaitForCorrectVersion(arg1 context.Context, arg2 int, arg3 string, arg4 []byte, arg5 runtime.ReadFileFunc) error { + var arg4Copy []byte + if arg4 != nil { + arg4Copy = make([]byte, len(arg4)) + copy(arg4Copy, arg4) + } + fake.waitForCorrectVersionMutex.Lock() + ret, specificReturn := fake.waitForCorrectVersionReturnsOnCall[len(fake.waitForCorrectVersionArgsForCall)] + fake.waitForCorrectVersionArgsForCall = append(fake.waitForCorrectVersionArgsForCall, struct { + arg1 context.Context + arg2 int + arg3 string + arg4 []byte + arg5 runtime.ReadFileFunc + }{arg1, arg2, arg3, arg4Copy, arg5}) + stub := fake.WaitForCorrectVersionStub + fakeReturns := fake.waitForCorrectVersionReturns + fake.recordInvocation("WaitForCorrectVersion", []interface{}{arg1, arg2, arg3, arg4Copy, arg5}) + fake.waitForCorrectVersionMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4, arg5) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeVerifyClient) WaitForCorrectVersionCallCount() int { + fake.waitForCorrectVersionMutex.RLock() + defer fake.waitForCorrectVersionMutex.RUnlock() + return len(fake.waitForCorrectVersionArgsForCall) +} + +func (fake *FakeVerifyClient) WaitForCorrectVersionCalls(stub func(context.Context, int, string, []byte, runtime.ReadFileFunc) error) { + fake.waitForCorrectVersionMutex.Lock() + defer fake.waitForCorrectVersionMutex.Unlock() + fake.WaitForCorrectVersionStub = stub +} + +func (fake *FakeVerifyClient) WaitForCorrectVersionArgsForCall(i int) (context.Context, int, string, []byte, runtime.ReadFileFunc) { + fake.waitForCorrectVersionMutex.RLock() + defer fake.waitForCorrectVersionMutex.RUnlock() + argsForCall := fake.waitForCorrectVersionArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4, argsForCall.arg5 +} + +func (fake *FakeVerifyClient) WaitForCorrectVersionReturns(result1 error) { + fake.waitForCorrectVersionMutex.Lock() + defer fake.waitForCorrectVersionMutex.Unlock() + fake.WaitForCorrectVersionStub = nil + fake.waitForCorrectVersionReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeVerifyClient) WaitForCorrectVersionReturnsOnCall(i int, result1 error) { + fake.waitForCorrectVersionMutex.Lock() + defer fake.waitForCorrectVersionMutex.Unlock() + fake.WaitForCorrectVersionStub = nil + if fake.waitForCorrectVersionReturnsOnCall == nil { + fake.waitForCorrectVersionReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.waitForCorrectVersionReturnsOnCall[i] = struct { + result1 error + }{result1} +} + +func (fake *FakeVerifyClient) Invocations() map[string][][]interface{} { + fake.invocationsMutex.RLock() + defer fake.invocationsMutex.RUnlock() + fake.ensureConfigVersionMutex.RLock() + defer fake.ensureConfigVersionMutex.RUnlock() + fake.getConfigVersionMutex.RLock() + defer fake.getConfigVersionMutex.RUnlock() + fake.waitForCorrectVersionMutex.RLock() + defer fake.waitForCorrectVersionMutex.RUnlock() + copiedInvocations := map[string][][]interface{}{} + for key, value := range fake.invocations { + copiedInvocations[key] = value + } + return copiedInvocations +} + +func (fake *FakeVerifyClient) recordInvocation(key string, args []interface{}) { + fake.invocationsMutex.Lock() + defer fake.invocationsMutex.Unlock() + if fake.invocations == nil { + fake.invocations = map[string][][]interface{}{} + } + if fake.invocations[key] == nil { + fake.invocations[key] = [][]interface{}{} + } + fake.invocations[key] = append(fake.invocations[key], args) +} diff --git a/internal/mode/static/nginx/runtime/verify.go b/internal/mode/static/nginx/runtime/verify.go index 4e3ff68732..9dc64d4e34 100644 --- a/internal/mode/static/nginx/runtime/verify.go +++ b/internal/mode/static/nginx/runtime/verify.go @@ -19,15 +19,29 @@ const configVersionURI = "/var/run/nginx/nginx-config-version.sock" var noNewWorkersErrFmt = "reload unsuccessful: no new NGINX worker processes started for config version %d." + " Please check the NGINX container logs for possible configuration issues: %w" -// verifyClient is a client for verifying the config version. -type verifyClient struct { +//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . nginxConfigVerifier + +type nginxConfigVerifier interface { + GetConfigVersion() (int, error) + WaitForCorrectVersion( + ctx context.Context, + expectedVersion int, + childProcFile string, + previousChildProcesses []byte, + readFile ReadFileFunc, + ) error + EnsureConfigVersion(ctx context.Context, expectedVersion int) error +} + +// VerifyClient is a client for verifying the config version. +type VerifyClient struct { client *http.Client timeout time.Duration } -// newVerifyClient returns a new client pointed at the config version socket. -func newVerifyClient(timeout time.Duration) *verifyClient { - return &verifyClient{ +// NewVerifyClient returns a new client pointed at the config version socket. +func NewVerifyClient(timeout time.Duration) *VerifyClient { + return &VerifyClient{ client: &http.Client{ Transport: &http.Transport{ DialContext: func(_ context.Context, _, _ string) (net.Conn, error) { @@ -39,9 +53,9 @@ func newVerifyClient(timeout time.Duration) *verifyClient { } } -// getConfigVersion gets the version number that we put in the nginx config to verify that we're using +// GetConfigVersion gets the version number that we put in the nginx config to verify that we're using // the correct config. -func (c *verifyClient) getConfigVersion() (int, error) { +func (c *VerifyClient) GetConfigVersion() (int, error) { ctx, cancel := context.WithTimeout(context.Background(), c.timeout) defer cancel() @@ -71,15 +85,15 @@ func (c *verifyClient) getConfigVersion() (int, error) { return v, nil } -// waitForCorrectVersion first ensures any new worker processes have been started, and then calls the config version +// WaitForCorrectVersion first ensures any new worker processes have been started, and then calls the config version // endpoint until it gets the expectedVersion, which ensures that a new worker process has been started for that config // version. -func (c *verifyClient) waitForCorrectVersion( +func (c *VerifyClient) WaitForCorrectVersion( ctx context.Context, expectedVersion int, childProcFile string, previousChildProcesses []byte, - readFile readFileFunc, + readFile ReadFileFunc, ) error { ctx, cancel := context.WithTimeout(ctx, c.timeout) defer cancel() @@ -93,7 +107,7 @@ func (c *verifyClient) waitForCorrectVersion( return fmt.Errorf(noNewWorkersErrFmt, expectedVersion, err) } - if err := c.ensureConfigVersion(ctx, expectedVersion); err != nil { + if err := c.EnsureConfigVersion(ctx, expectedVersion); err != nil { if errors.Is(err, context.DeadlineExceeded) { err = fmt.Errorf( "config version check didn't return expected version %d within the deadline", @@ -105,13 +119,13 @@ func (c *verifyClient) waitForCorrectVersion( return nil } -func (c *verifyClient) ensureConfigVersion(ctx context.Context, expectedVersion int) error { +func (c *VerifyClient) EnsureConfigVersion(ctx context.Context, expectedVersion int) error { return wait.PollUntilContextCancel( ctx, 25*time.Millisecond, true, /* poll immediately */ func(_ context.Context) (bool, error) { - version, err := c.getConfigVersion() + version, err := c.GetConfigVersion() return version == expectedVersion, err }, ) @@ -121,7 +135,7 @@ func ensureNewNginxWorkers( ctx context.Context, childProcFile string, previousContents []byte, - readFile readFileFunc, + readFile ReadFileFunc, ) error { return wait.PollUntilContextCancel( ctx, diff --git a/internal/mode/static/nginx/runtime/verify_test.go b/internal/mode/static/nginx/runtime/verify_test.go index fda58b56f3..34982f48be 100644 --- a/internal/mode/static/nginx/runtime/verify_test.go +++ b/internal/mode/static/nginx/runtime/verify_test.go @@ -30,7 +30,7 @@ func getTestHTTPClient() *http.Client { } func TestVerifyClient(t *testing.T) { - c := verifyClient{ + c := VerifyClient{ client: getTestHTTPClient(), timeout: 25 * time.Millisecond, } @@ -50,7 +50,7 @@ func TestVerifyClient(t *testing.T) { tests := []struct { ctx context.Context - readFile readFileFunc + readFile ReadFileFunc name string expectedVersion int expectError bool @@ -89,7 +89,7 @@ func TestVerifyClient(t *testing.T) { t.Run(test.name, func(t *testing.T) { g := NewWithT(t) - err := c.waitForCorrectVersion(test.ctx, test.expectedVersion, "/childfile", []byte("1 2 3"), test.readFile) + err := c.WaitForCorrectVersion(test.ctx, test.expectedVersion, "/childfile", []byte("1 2 3"), test.readFile) if test.expectError { g.Expect(err).To(HaveOccurred()) @@ -126,7 +126,7 @@ func TestEnsureNewNginxWorkers(t *testing.T) { tests := []struct { ctx context.Context - readFile readFileFunc + readFile ReadFileFunc name string previousContents []byte expectError bool