-
Notifications
You must be signed in to change notification settings - Fork 8
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 mocking to Cyclops #85
Conversation
pkg/cloudprovider/aws/builder.go
Outdated
@@ -40,3 +42,11 @@ func NewCloudProvider(logger logr.Logger) (cloudprovider.CloudProvider, error) { | |||
|
|||
return p, nil | |||
} | |||
|
|||
// NewMockCloudProvider returns a new mock AWS cloud provider | |||
func NewMockCloudProvider(autoscalingiface autoscalingiface.AutoScalingAPI, ec2iface ec2iface.EC2API) cloudprovider.CloudProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really returning a new mock AWS cloud provider or just a new provider that could either be the real thing or mocked depending on what is passed in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think this doesn't have to be NewMockCloudProvider
but could just be NewCloudProvider
where the two interfaces passed in are the mocks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, it's not necessarily mocking.
pkg/mock/phase_pending_test.go
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an appropriate location in the codebase for testing the Pending phase? I'd have thought these tests would be better located with the phase implementations themselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the mock package should only contain things to do with creating / setting up / tearing down mocks. Tests themselves belong with the code file that implements them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately that leads to an import cycle so this is the best place I could think of putting it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mock for an individual piece of functionality can live next to the code too, I've seen this happen in quite a few code bases. That avoids the import cycle. You just import generic mocking functionality from the central package in that situation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately that leads to an import cycle so this is the best place I could think of putting it
If this is occurring and as @mwhittington21 suggests we'll need to make the mocking package more generic and moving mocking logic to where it makes sense (probably next to the thing it is mocking)
pkg/mock/phase_pending_test.go
Outdated
}, | ||
}, | ||
NodeNames: []string{ | ||
"node-0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess one nit here is in this test we're assuming that when you create a test node group with newNodegroup()
that nodes follow this naming scheme.
Someone modifying newNodegroup()
may find they break a ton of tests if they decide to change an assumption on how test node groups are created
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could possibly remedy this by adding a node that obviously would very obviously never exist in the NodeNames
field
pkg/mock/phase_pending_test.go
Outdated
assert.NoError(t, err) | ||
assert.Equal(t, v1.CycleNodeRequestPending, mockTransitioner.Cnr.Status.Phase) | ||
|
||
// Simulate waiting for 1 day, this is more than the waiting limit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we assuming the waiting limit is always < 24 hours? Can we make this an input into the test, so that someone changing the wait limit doesn't break unrelated tests
} | ||
|
||
// SetDesiredCapacity mock implementation for MockAutoscalingService | ||
func (m MockAutoscalingService) SetDesiredCapacity(*autoscaling.SetDesiredCapacityInput) (*autoscaling.SetDesiredCapacityOutput, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I notice we've not implemented functions like this in the new mock AWS - do we not need them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will implement functionality as needed. As I add new features in upcoming PRs I will add the functionality for the mocking to support the appropriate tests.
pkg/mock/util.go
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this file test_helpers.go
or something so more things don't pile into it over time. util.go
is likely to attract more cruft.
pkg/cloudprovider/aws/builder.go
Outdated
@@ -40,3 +42,11 @@ func NewCloudProvider(logger logr.Logger) (cloudprovider.CloudProvider, error) { | |||
|
|||
return p, nil | |||
} | |||
|
|||
// NewMockCloudProvider returns a new mock AWS cloud provider | |||
func NewMockCloudProvider(autoscalingiface autoscalingiface.AutoScalingAPI, ec2iface ec2iface.EC2API) cloudprovider.CloudProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think this doesn't have to be NewMockCloudProvider
but could just be NewCloudProvider
where the two interfaces passed in are the mocks.
pkg/mock/phase_pending_test.go
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the mock package should only contain things to do with creating / setting up / tearing down mocks. Tests themselves belong with the code file that implements them.
pkg/mock/util.go
Outdated
} | ||
|
||
node := &Node{ | ||
Name: fmt.Sprintf("node-%d", i), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I create two NodeGroups for a test, is there a problem if the groups contain the same named nodes? With the current implementation this will happen. I suspect this is not intentional, and the node names should probably be generated such that they aren't shared between NodeGroups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, I can add the nodegroup name to the node name to help get around this.
pkg/mock/util.go
Outdated
nodes := make([]*Node, 0) | ||
|
||
for i := 0; i < num; i++ { | ||
instanceID, err := generateRandomInstanceId() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're ever doing a test that wants to look for specific instance IDs you will want a way to customise this. Not sure if it's worth adding now or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more of a helper, instance IDs can be made custom when someone would want to create a node without it.
pkg/mock/client.go
Outdated
return nil | ||
} | ||
|
||
func generateFakeInstances(nodes []*Node) *[]*fakeaws.Instance { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason to returning a pointer to a slice?
pkg/cloudprovider/aws/fake/fake.go
Outdated
type Ec2 struct { | ||
ec2iface.EC2API | ||
|
||
Instances *[]*Instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to my other comment on pointer to a slice - why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was to take into terminating instances using the ec2 instance and then describing asgs using the autoscaling instance and I want them to be in sync. I've done some testing and changed this to a map to make it easier to manage those fake instances in the future and it works as I'd like.
Pending
phase and includes the required functionality for that.