Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for runtime manager #1555

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

zedGGs
Copy link

@zedGGs zedGGs commented Feb 9, 2024

Proposed changes

Problem: Missing tests on runtime manager

Im adding this init pr with few tests, if this goes well I can add another pr with more tests

gentle ping for @sjberman

Solution: Added tests and tested locally

Testing: running go test locally

optional: additional questions to clarify mocking and provide more details

Is practice for mocking runtime manager, more to use current usage with:
mgr = NewManagerImpl(&ngxclient.NginxClient{}, nil, logr.New(GinkgoLogr.GetSink()))

or I can use already created mock from runtimefakes:
runtimefakes.FakeManager as mocked struct, even tho its mocked interface ?

or its required to actually mock MetricsCollector in runtimefakes by creating runtimefakes.FakeMetricsCollector with counterfeiter and then use that one, in
NewManagerImpl(&ngxclient.NginxClient{}, &runtmefakes.FakeMetricCollector{}, logr.New(GinkgoLogr.GetSink()))

or in

mockedManager := &runtimefakes.FakeManager{}

any advice on this is appreciated a lot, thank you in advance

Closes #1498

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

@zedGGs zedGGs requested a review from a team as a code owner February 9, 2024 12:34
@github-actions github-actions bot added the tests Pull requests that update tests label Feb 9, 2024
@zedGGs zedGGs force-pushed the test/add-runtime-manager-tests branch from ec34013 to 99997c4 Compare February 9, 2024 12:58
@sjberman
Copy link
Contributor

sjberman commented Feb 9, 2024

@zedGGs To answer your question about mocking, one of the goals of this work is to test out the ManagerImpl functions in manager.go. So this means we'll need to use the real ManagerImpl implementation, but be able to mock out the components that it uses, so we ensure we're just testing the ManagerImpl.

@zedGGs
Copy link
Author

zedGGs commented Feb 10, 2024

@sjberman sounds good,
thank you for the feedback and review, Im going to proceed accordingly

@zedGGs zedGGs requested a review from sjberman February 16, 2024 19:36
@zedGGs
Copy link
Author

zedGGs commented Feb 16, 2024

@sjberman apologies for not being on time with an update,

current test cases for ManagerImpl are for situations where theres an error,
I can say I had little issues to properly mock correct upstreams on nginx client, so I have not added these test cases,
even tho I tried to do this, I can say I actually don't know how this works, any advice is appreciated

thank you in advance !

if you want you can take current changes and I can add separated pr for good test cases,

issue happens to be:

failed to update servers of unknown upstream: failed to get the HTTP servers of upstream unknown: failed to get http/upstreams/unknown/servers: Get "http://10.0.0.1:80/9/http/upstreams/unknown/servers": context deadline exceeded (Client.Timeout exceeded while awaiting headers)

			serversMock = ngxclient.UpstreamServer{
				ID:          1,
				Server:      "10.0.0.1:80",
				MaxConns:    &MaxConnsMock,
				MaxFails:    &MaxFailsMock,
				FailTimeout: "test",
				SlowStart:   "test",
				Route:       "test",
				Backup:      &BackupMock,
				Down:        &DownMock,
				Drain:       false,
				Weight:      &WeightMock,
				Service:     "",
			}

with ngxclient.NewNginxClient("10.0.0.1:80", client.WithHTTPClient(httpClient))

@zedGGs zedGGs force-pushed the test/add-runtime-manager-tests branch from b84583c to b36adc6 Compare February 16, 2024 19:56
@sjberman
Copy link
Contributor

@zedGGs Thanks for the update. The issue you're seeing is that the nginx client is attempting to reach a real server, and fails. For unit tests we obviously do not want to use a real server. This means we probably need to create interfaces in https://github.com/nginxinc/nginx-plus-go-client, so we can provide a mock client in our own unit tests that won't try to contact a real server.

@zedGGs zedGGs requested a review from sjberman February 20, 2024 06:09
@zedGGs
Copy link
Author

zedGGs commented Feb 20, 2024

@sjberman here's an update, I have added NginxPlusClient to use UpdateHTTPServers and GetUpstreams since they are only being used currently,
can add more improvements in test overall if you think something can be better

thanks

@zedGGs zedGGs force-pushed the test/add-runtime-manager-tests branch from 4663750 to 0b42d66 Compare February 20, 2024 06:21
@sjberman
Copy link
Contributor

It would be nice if we could also find a way to test the Reload() function. May require temporary files and another client mock.

@zedGGs
Copy link
Author

zedGGs commented Feb 21, 2024

@kate-osborn sure, I am going to try add tests for that too
thanks for feedback !!

Copy link
Contributor

This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added the stale Pull requests/issues with no activity label Mar 12, 2024
@zedGGs zedGGs requested a review from sjberman March 12, 2024 18:46
@sjberman sjberman removed the stale Pull requests/issues with no activity label Mar 12, 2024
internal/mode/static/manager.go Outdated Show resolved Hide resolved
internal/mode/static/manager.go Outdated Show resolved Hide resolved
internal/mode/static/manager.go Outdated Show resolved Hide resolved
@mpstefan mpstefan added this to the v1.3.0 milestone Mar 20, 2024
Copy link
Contributor

github-actions bot commented Apr 4, 2024

This PR is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 14 days.

@github-actions github-actions bot added the stale Pull requests/issues with no activity label Apr 4, 2024
Copy link
Contributor

This PR was closed because it has been stalled for 14 days with no activity.

@github-actions github-actions bot closed this Apr 18, 2024
@mpstefan
Copy link
Collaborator

Reopening after discussion with Zedd!

@mpstefan mpstefan reopened this Apr 22, 2024
@sjberman sjberman removed the stale Pull requests/issues with no activity label Apr 22, 2024
@zedGGs zedGGs force-pushed the test/add-runtime-manager-tests branch from a172d77 to 8d57c25 Compare May 20, 2024 14:48
@zedGGs zedGGs requested a review from sjberman May 20, 2024 14:50
internal/mode/static/manager.go Outdated Show resolved Hide resolved
internal/mode/static/nginx/runtime/manager.go Outdated Show resolved Hide resolved
internal/mode/static/nginx/runtime/manager.go Outdated Show resolved Hide resolved
internal/mode/static/nginx/runtime/manager_test.go Outdated Show resolved Hide resolved
internal/mode/static/nginx/runtime/manager_test.go Outdated Show resolved Hide resolved
internal/mode/static/nginx/runtime/manager_test.go Outdated Show resolved Hide resolved
@zedGGs zedGGs requested a review from sjberman May 20, 2024 15:22
Copy link

codecov bot commented May 20, 2024

Codecov Report

Attention: Patch coverage is 47.82609% with 12 lines in your changes are missing coverage. Please review.

Project coverage is 87.30%. Comparing base (6f709fe) to head (b5ccf05).

Files Patch % Lines
internal/mode/static/nginx/runtime/manager.go 50.00% 6 Missing and 1 partial ⚠️
internal/mode/static/manager.go 0.00% 3 Missing ⚠️
internal/mode/static/nginx/runtime/verify.go 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1555      +/-   ##
==========================================
+ Coverage   87.04%   87.30%   +0.26%     
==========================================
  Files          89       89              
  Lines        6096     6103       +7     
  Branches       50       50              
==========================================
+ Hits         5306     5328      +22     
+ Misses        737      716      -21     
- Partials       53       59       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

type verifyClient struct {
//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . verifyClient

type verifyClient interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type verifyClient interface {
type nginxConfigVerifier interface {

Then we can keep the struct names verifyClient and avoid adding Impl to the name, which is technically an anti-pattern.

@@ -134,7 +137,7 @@ func StartManager(cfg config.Config) error {
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's create processHandler here right before it's used.

@@ -17,18 +17,36 @@ import (
)

const (
pidFile = "/var/run/nginx/nginx.pid"
PidFile = "/var/run/nginx/nginx.pid"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add comments to all the newly exported variables and types.


//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . ProcessHandler

type ProcessHandler interface {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can simplify this interface.


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(readFileFunc ReadFileFunc, checkFileFunc CheckFileFunc) *ProcessHandlerImpl {
	return &ProcessHandlerImpl{readFile: readFileFunc, checkFile: checkFileFunc}
}

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)
}
...

Other changes:

  • FindMainProcess will use the readFile and checkFile funcs that are stored on ProcessHandlerImpl.
  • EnsureNginxRunning method is removed. In static/manager.go replace call to EnsureNginxRunning with processHandler.FindMainProcess.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also don't think ProcessHandler needs to be exported since it's not used outside of this file.

Expect(process.KillCallCount()).To(Equal(1))
Expect(metrics.IncReloadCountCallCount()).To(Equal(1))
Expect(verifyClient.WaitForCorrectVersionCallCount()).To(Equal(1))
Expect(metrics.ObserveLastReloadTimeCallCount()).To(Equal(1))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's also check that the IncReloadErrorsCallCount is 0.

})

When("NGINX configuration reload is not successful", func() {
It("should panic if MetricsCollector not enabled", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use the following structure when testing for panics:

When("MetricsCollector is nil")
It("panics")

Expect(metrics.ObserveLastReloadTimeCallCount()).To(Equal(1))
})

When("NGINX configuration reload is not successful", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a different test case from the panics in the blocks below. We really want to test reload failures, which happens in the following cases:

  • failed to find main process
  • failed to read file
  • failed to send kill signal
  • timed out waiting for correct version

I think we want a test for each one of these cases. You can configure the mocks to return errors to trigger these cases.

Expect(manager.UpdateHTTPServers("test", upstreamServers)).To(Succeed())
})

It("returns no upstreams from NGINX Plus API", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are missing a test case here. This test covers the case where the upstreams are nil, but we still need to cover the case where the ngxPlusClient returns an error for GetUpstreams:

upstreams, err := m.ngxPlusClient.GetUpstreams()

You can do this by configuring the mock to return an error for the method GetUpstreams

It("successfully updates HTTP server upstream", func() {
Expect(manager.UpdateHTTPServers("test", upstreamServers)).To(Succeed())
})

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we also need a test for the success case. Let's add upstream servers to the mock and test that they are returned by manager.GetUpstreams

})

It("successfully updates HTTP server upstream", func() {
Expect(manager.UpdateHTTPServers("test", upstreamServers)).To(Succeed())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also check that we called the mock's UpdateHTTPServers method here with the input "test"

)

var childProcPathFmt = "/proc/%[1]v/task/%[1]v/children"

//go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 . nginxPlusClient
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1990 was just merged that changes how we specify these generation statements now, take a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
community tests Pull requests that update tests
Projects
Status: External Pull Requests
Development

Successfully merging this pull request may close these issues.

Add unit tests for nginx runtime manager
5 participants