Skip to content

Conversation

@ankush-ntx
Copy link
Contributor

@ankush-ntx ankush-ntx commented May 5, 2025

Summary:

This PR introduces a testing framework for the Nutanix COSI driver, including both unit tests and end-to-end (E2E) tests. In addition, several minor bugs discovered during test development have been addressed and resolved.

Changes:

Unit Tests:

  • Covers core driver logic, IAM client ops, S3 client ops and provisioner methods.
  • Mocks for S3 client and IAM client to isolate functionality.

E2E Tests:

  • Tests all the workflows completely with edge cases.
  • Including: Create/Delete buckets, Grant/Revoke user access
  • Tests can be run on both a real cluster or a local cluster using Objects Triton as S3 backend objects store.

CI/CD Pipeline:

  • Updated GitHub pipeline to include running unit tests when a PR is created.

Deployment Changes:

  • PC_SECRET now only contains username and password credentials for the Prism Central in the previous format.
  • PC_ENDPOINT instead should have the full endpoint of the Prism Central.

Fixes:

How to run tests?

Unit Tests:
Execute the following to run unit tests:

go test ./...

To generate the coverage report and an HTML page to view the report:

go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html

Open the HTML file in any web browser to view the coverage of each file.

E2E Tests:
Execute the following to run E2E tests:

sh scripts/setup_test_env.sh [flags]
Options:
-o, --oss_endpoint ENDPOINT    Nutanix Object Store instance endpoint, eg. "http://10.51.142.82:80".
-i, --pc_endpoint ENDPOINT     Prism Central endpoint, eg. "https://10.51.142.82:9440".
-u, --pc_user USERNAME         Prism Central username. [default = admin]
-p, --pc_pass PASSWORD         Prism Central password.
-a, --access_key KEY           Admin IAM Access key to be used for Nutanix Objects.
-s, --secret_key KEY           Admin IAM Secret key to be used for Nutanix Objects.
-n, --namespace NAMESAPCE      Cluster namespace for the COSI deployment [default = cosi]

Check the README.md for more info.

Copy link

@anirudhbansal95 anirudhbansal95 left a comment

Choose a reason for hiding this comment

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

Thanks Ankush. Reviewed the unit tests and the associated code. Yet to review the end to end tests.

return fmt.Errorf("%s", delete_resp.Status)
if delete_resp.StatusCode == 404 {
return nil
} else if delete_resp.StatusCode != 204 {

Choose a reason for hiding this comment

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

nit: else if can be removed from line 165 since we are returning in line 164

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.


t.Run("TestCreateUser_MissingUsername", func(t *testing.T) {
api := &admin.API{}
_, err := api.CreateUser(ctx, "", mockDisplayName)

Choose a reason for hiding this comment

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

Currently we allow the display name to be empty, though not the user name. Is this the expected behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes. The API call is valid even with empty displayName.

api := admin.API{
AccountName: "test",
}
accountName := api.AccountName

Choose a reason for hiding this comment

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

Maybe use api.GetAccountName() here and in the test below

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.

klog.ErrorS(err, "failed to delete user")
}

klog.InfoS("Successfully revoked access of user", "userName", req.GetAccountId(), "bucketName", req.GetBucketId())

Choose a reason for hiding this comment

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

Do we also need to update the bucket policy here to remove the user from it, like we updated the bucket policy to grant user access in the previous case?

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. Changed policy SID to userId instead of username to facilitate policy removal when deleting bucket access.

foundSID1 = true
assert.Equal(t, "Deny", string(ps.Effect))
case "sid2":
foundSID2 = true

Choose a reason for hiding this comment

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

Maybe also check that sid2 and sid3 have "Allow" effect

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.

ps.Allows()
assert.Equal(t, s3client.Effect("Allow"), ps.Effect)
ps.Effect = "Other"
ps.Allows()

Choose a reason for hiding this comment

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

nit: Maybe add a comment that ps.Allows() doesn't modify an existing effect, if set.

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.

s := &s3client.S3Agent{Client: mock}
content, err := s.GetObjectInBucket("missing-bucket", "missing-key")
assert.Error(t, err)
assert.Equal(t, "ERROR_ OBJECT NOT FOUND", content)

Choose a reason for hiding this comment

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

Is this a specific format in which the object not found error should be returned? Or can it be something like: ERROR_OBJECT_NOT_FOUND or some other string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Returning empty string now with error.

Copy link

@anirudhbansal95 anirudhbansal95 left a comment

Choose a reason for hiding this comment

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

Thanks Ankush. Took a look at the end to end tests. They look good in general with a few comments.

return err
}

if bucket.Status.BucketReady == false {

Choose a reason for hiding this comment

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

nit: if !bucket.Status.BucketReady

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.

return err
}

if bucket.Status.BucketReady == true {

Choose a reason for hiding this comment

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

nit: if bucket.Status.BucketReady

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.

Expect(err).ToNot(HaveOccurred())

// By("Checking if Bucket is created in the Objectstore backend")
err = s3Client.WaitUntilBucketExists(&s3.HeadBucketInput{Bucket: &failBucket.Name})

Choose a reason for hiding this comment

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

Do we need to call this function in other tests as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

CheckBucketExistenceInObjectstore()already waits for bucket creating, so removed WaitUntilBucketExists() as it is redundant.

1. Changed policy SID to userId instead of username to facilitate
policy removal when deleting bucket access.

2. Updated policy functions to handle single element Action,
Resource and Principal.
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.

Deleting a Bucket object with a missing bucket fails

2 participants