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

Refactored S3 test cases to remove repetition and use table drive tests #110

Merged
merged 5 commits into from Jun 11, 2020

Conversation

saurabh-hirani
Copy link
Contributor

@saurabh-hirani saurabh-hirani commented Apr 18, 2020

The current code for s3_test.go has the following issues:

  • Test cases which should be subtests are added as individual tests.
  • Testing var t is passed throughout the code and should be consolidated to be used only with tests.
  • There is no support for table drive tests to make it easier to add more test cases.
  • While we are testing only list and nuke operations for buckets, it is not apparent from the test cases.

Refactored the code to fix the above issues. This has no impact on the current functionality as only the s3_test.go file has changed. This activity is also to ensure that adding cases for tagged and named deletions in the future is easier.

* Remove passing testing var t all across the code
* Reduce repetitive main tests and add subtests
* Subtests simplified in 2 categories - TestList and TestNuke
* Have subtests generated via returned test functions to avail
  table driven tests
@saurabh-hirani
Copy link
Contributor Author

@yorinasub17 @brikis98 - can you please check and let me know if this looks okay? Thanks.

Copy link
Member

@brikis98 brikis98 left a comment

Choose a reason for hiding this comment

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

Thanks for the PR!

GitHub is not doing a great job of rendering the diff, so this was quite hard to read and compare the old to the new. Would appreciate a second set of eyes @yorinasub17.

aws/s3_test.go Outdated
// genTestsBucketName generates a test bucket name.
func genTestBucketName() string {
// Call UniqueID twice because even if the nth test tries to reuse a name of the first test
// AWS S3 deletion operation might be in progress after nuking.
Copy link
Member

Choose a reason for hiding this comment

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

Not sure I understand this explanation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wanted to have a little bit more randomness but yes the comment isn't clear and not needed. Removed.

aws/s3_test.go Outdated
objectCount int
objectBatchsize int
// setAWSParams sets up common operations for nuke S3 tests.
func setAWSParams() (AWSParams, error) {
Copy link
Member

Choose a reason for hiding this comment

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

NIT: perhaps newAWSParams?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

aws/s3_test.go Outdated
// Verify that - before creating bucket - it should not exist
//
// Please note that we are not reusing awsParams.awsSession and creating a random session in a region other
// than the one in which the bucket is created - this is useful to test the sceanrio where the user has
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// than the one in which the bucket is created - this is useful to test the sceanrio where the user has
// than the one in which the bucket is created - this is useful to test the scenario where the user has

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

aws/s3_test.go Outdated
if err == nil {
assert.Fail(t, "Did not fail for invalid batch size")
}
t.Logf("SUCCESS: Did not list buckets due to invalid batch size - %s", bucket.name)
Copy link
Member

Choose a reason for hiding this comment

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

We should not be using t.Logf for logging.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

aws/s3_test.go Outdated
Comment on lines 249 to 256
type testCaseStruct struct {
name string
args TestListS3BucketArgs
}
}

func TestList_EmptyS3Bucket_NoTags(t *testing.T) {
testListS3BucketsWrapper(t, []map[string]string{}, 10, true)
}
var allTestCases []testCaseStruct

func TestList_EmptyS3Bucket_WithoutFilterTag(t *testing.T) {
testListS3BucketsWrapper(t, []map[string]string{
testCases := []testCaseStruct{
Copy link
Member

Choose a reason for hiding this comment

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

NIT: The Go idiom typically used for table-driven tests declares the struct and the tests all in one:

var testCases = []struct {
	param1 string
	param2 string
}{
	{"aaa", "bbb"},
	{"ccc", "ddd"},
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done for TestListS3Bucket . For TestNukeS3Bucket as per -

for _, bucketType := range []string{"NoVersioning", "Versioning"} {
- as we need to generate tests both for versioned and non versioned buckets - we have to create list of tests first and then execute them.

aws/s3_test.go Outdated

targetRegions := []string{awsParams.region}

return func(t *testing.T) {
Copy link
Member

Choose a reason for hiding this comment

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

t.Parallel()?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

aws/s3_test.go Show resolved Hide resolved
* Not using t.Logf
* Fixing typos
* Using t.Parallel in sub and main tests
* Using idomatic golang test struct where possible
@saurabh-hirani
Copy link
Contributor Author

@brikis98 @yorinasub17 - updated as per feedback.

Copy link
Contributor

@yorinasub17 yorinasub17 left a comment

Choose a reason for hiding this comment

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

The update makes sense, but I am not sure this is the best implementation for readability. I think my biggest challenge with this is the test function generator pattern.

I think it would be easier to follow and understand what is going on if there was instead a function to drive the test runNukeTest(t *testing.T, args *Args) that then contains the combination of the generator routine and subtest function. Then, usage would be:

		t.Run(tc.name, func(t *testing.T) { runNukeTest(t, tc.args) })

This removes one layer of indirection and should help make it much easier to follow what is going on. What do you think?

aws/s3_test.go Show resolved Hide resolved
aws/s3_test.go Outdated
isVersioned := false
if bucketType == "Versioning" {
isVersioned = true
}
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT:

isVersioned := bucketType == "Versioning"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

* Remove one level of indirection by combining
  subtest and setup for S3 list and nuke tests
@saurabh-hirani
Copy link
Contributor Author

This removes one layer of indirection and should help make it much easier to follow what is going on. What do you think?

Thanks - that would lead to cleaner code. Fixed it.

@saurabh-hirani
Copy link
Contributor Author

@yorinasub17 - updated as per feedback.

@saurabh-hirani
Copy link
Contributor Author

saurabh-hirani commented May 13, 2020

@yorinasub17 - just wanted to check if the above looks good - I have updated the code as per your feedback. Thanks.

@yorinasub17
Copy link
Contributor

Hi @saurabh-hirani apologies for the delay on this. I've been super booked this month and haven't had the time to look at this. I am hoping to be able to review this again next week.

Copy link
Contributor

@yorinasub17 yorinasub17 left a comment

Choose a reason for hiding this comment

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

Apologies for the long review cycle this time. I had to put this off multiple times, but finally had the time to look. This is very close, but had a few style nits.

I am committed to moving this across the finish line in the next two weeks. Let me know if you are not able to handle the updates, and I can try to find time to apply them myself.

Region: awsgo.String(region)},
)
return session, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: since the namespace is shared across the entire package, this should probably be put in a different place or renamed to something specific to s3 tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done - added S3Test prefix where possible for consistency.

region string
awsSession *session.Session
svc *s3.S3
bucketName string
}
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: rename to something that is specific to S3.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This has been removed so not applicable.

aws/s3_test.go Outdated
// TestS3Bucket represents a test S3 bucket
type TestS3Bucket struct {
name string
tags []map[string]string
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: consider using the structs from aws sdk for type safety.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Checked and saw that there is no need for TestS3Bucket struct - easier to have functions which take args and instead of using types and getting into potential conflicts with AWS. create and addObject have been replaced by S3TestCreateBucket and S3TestBucketAddObject

aws/s3_test.go Outdated
if err != nil {
assert.Fail(t, errors.WithStackTrace(err).Error())
assert.Failf(t, "Failed to setup AWS params", errors.WithStackTrace(err).Error())
Copy link
Contributor

Choose a reason for hiding this comment

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

Use require.Fail or require.NoError to cut the test short. Otherwise, execution will continue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks - wasn't aware of that - have used require.NoError - removes the if/else check also.

aws/s3_test.go Outdated
allTestCases = append(allTestCases, testCaseStruct{
"EmptyBucket",
TestNukeS3BucketArgs{isVersioned: false, checkDeleteMarker: false, objectCount: 0, objectBatchsize: 0, shouldNuke: true},
})
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: statically define the list like you did in the other test instead of using append, for consistency.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did that - had optimised in this case as EmptyBucket test does not need to deal with versioned/non-versioned flags but moved it in.

}, true)
}
for _, bucketType := range []string{"NoVersioning", "Versioning"} {
isVersioned := bucketType == "Versioning"
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: use true and false directly in the range var.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Cannot do so as the tests need the Versioning v/s NonVersioning prefix

--- PASS: TestNukeS3Bucket/NoVersioning_EmptyBucket (9.39s)
    --- PASS: TestNukeS3Bucket/NoVersioning_BatchObjects_InvalidBatchSize_Over (9.97s)
    --- PASS: TestNukeS3Bucket/Versioning_EmptyBucket (9.60s)
    --- PASS: TestNukeS3Bucket/Versioning_AllObjects (24.06s)

Having true/false in range will lead to reinterpreting true false and setting Versioning/nonVersioning

Copy link
Contributor

Choose a reason for hiding this comment

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

You could do:

fmt.Sprintf("Versioning_%v_EmptyBucket", isVersioning)

But it's not a big deal so can keep this as is.

aws/s3_test.go Show resolved Hide resolved
@saurabh-hirani
Copy link
Contributor Author

Apologies for the long review cycle this time. I had to put this off multiple times, but finally had the time to look. This is very close, but had a few style nits.

I am committed to moving this across the finish line in the next two weeks. Let me know if you are not able to handle the updates, and I can try to find time to apply them myself.

Thanks @yorinasub17 - will check out the changes today and reply back in the next 1-2 days.

* Add S3Test prefix to avoid conflicts with other files
  in this namespace + AWS core libs
* Use require.NoError
* Remove TestS3Bucket type and use direct functions
@saurabh-hirani
Copy link
Contributor Author

@yorinasub17 updated as per feedback and added comments. Please check and let me know if this looks good.

@saurabh-hirani
Copy link
Contributor Author

@yorinasub17 - can you please review the above changes and provide feedback if any more changes are required?

@yorinasub17
Copy link
Contributor

Apologies for the delay. I had been snoozing this and lost track of it amongst all the other things on my plate. I just took a pass and the updates look reasonable, so kicked off a build.

If that passes, we can go ahead and merge this in. Thanks!

@yorinasub17
Copy link
Contributor

Ok build passed! Will merge this in. Thanks for your contribution!

@yorinasub17 yorinasub17 merged commit 5f9bc56 into gruntwork-io:master Jun 11, 2020
@saurabh-hirani
Copy link
Contributor Author

Thanks @yorinasub17 and @brikis98 for the feedback!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants