Skip to content

HDDS-6528. Adding Unit-Test cases for S3-Gateway Bucket-Endpoint Metrics.#3263

Merged
jojochuang merged 7 commits intoapache:masterfrom
ArafatKhan2198:HDDS-6528
Apr 12, 2022
Merged

HDDS-6528. Adding Unit-Test cases for S3-Gateway Bucket-Endpoint Metrics.#3263
jojochuang merged 7 commits intoapache:masterfrom
ArafatKhan2198:HDDS-6528

Conversation

@ArafatKhan2198
Copy link
Contributor

@ArafatKhan2198 ArafatKhan2198 commented Apr 1, 2022

What changes were proposed in this pull request?

Added Unit Tests for Bucket Endpoint Metrics for S3-Gateway

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-6528

How was this patch tested?

Wrote Unit tests for existing metrics

@jojochuang @aryangupta1998 @siddhantsangwan @adoroszlai

@adoroszlai adoroszlai changed the title Adding Unit-Test cases for S3-Gateway Bucket-Endpoint Metrics. HDDS-6528. Adding Unit-Test cases for S3-Gateway Bucket-Endpoint Metrics. Apr 4, 2022
Copy link
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

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

Thanks @ArafatKhan2198 for working on this. There is compile error due to recent change on master (HDDS-6466). Can you please merge origin/master into your branch?

Comment on lines 142 to 156
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you please add separate test cases (methods) for success/failure scenarios instead of bundling them in the same?

Copy link
Contributor Author

@ArafatKhan2198 ArafatKhan2198 Apr 6, 2022

Choose a reason for hiding this comment

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

Each method is associated with a single S3 Endpoint and there are 2 metrics associated with each endpoint, hence we are measuring the number of times a method succeeds and fails, and once an object is initialised we can reuse it for both the metrics, therefore I felt clubbing them together would make more sense !!

Copy link
Contributor

Choose a reason for hiding this comment

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

Each method is associated with a single S3 Endpoint and there are 2 metrics associated with each endpoint, hence we are measuring the number of times a method succeeds and fails, and once an object is initialised we can reuse it for both the metrics

Currently each test method is associated with a method on one of the endpoints. E.g. testCreateBucket tests bucketEndpoint.put(), while testDeleteBucket tests bucketEndpoint.delete(). If object reuse is so important, why not merge all these together in a huge testBucketEndpoint method?

The reasons for separating these are at least:

  1. Small, self-contained test methods are easier to understand.
  2. Independence: test cases may pass or fail regardless of the result of other test cases. If multiple cases are bundled in the same method, failure of one case may hide the result of the subsequent case.

We can apply the same reasons to testing different metrics on the same endpoint and method pairs.

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 you are absolutely right on that part, I'll make the necessary changes
Thanks for the help !!

Copy link
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

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

Thanks @ArafatKhan2198 for updating the patch. On second look I've found a few more issues.

}

private OzoneClient createClientWithKeys(String... keys) throws IOException {
OzoneClient client = new OzoneClientStub();
Copy link
Contributor

Choose a reason for hiding this comment

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

setup() already creates a clientStub, why is this new client needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am sorry I forgot to remove it !!
will change it, thanks !!

Comment on lines 150 to 151
LOG.debug("Bucket Does not Exist " + bucketName, ex);
throw newError(S3ErrorTable.NO_SUCH_BUCKET, bucketName, ex);
Copy link
Contributor

Choose a reason for hiding this comment

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

We should just rethrow ex, because:

  • OS3Exception already has an error code and proper message. No need to wrap in another exception.
  • Cause may be different, not necessarily NO_SUCH_BUCKET.

On second thought we also don't need the debug message, because the exception is logged at debug level in newError.

if (e.getHttpCode() == HTTP_INTERNAL_ERROR) {
LOG.error("Internal Error: {}", err.toXml(), ex);
} else if (LOG.isDebugEnabled()) {
LOG.debug(err.toXml(), ex);
}

Suggested change
LOG.debug("Bucket Does not Exist " + bucketName, ex);
throw newError(S3ErrorTable.NO_SUCH_BUCKET, bucketName, ex);
throw ex;

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 we should just increment the counter and retrhwo

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure will do !!

Comment on lines 416 to 417
LOG.debug("Failed to get acl of Bucket " + bucketName, ex);
throw newError(S3ErrorTable.NO_SUCH_BUCKET, bucketName, ex);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here:

Suggested change
LOG.debug("Failed to get acl of Bucket " + bucketName, ex);
throw newError(S3ErrorTable.NO_SUCH_BUCKET, bucketName, ex);
throw ex;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will make the change, thanks !!

throw exception;
} catch (OS3Exception ex) {
getMetrics().incPutAclFailure();
LOG.debug("Failed to put acl of Bucket " + bucketName, ex);
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need the debug message, because the exception is logged at debug level in newError.

if (e.getHttpCode() == HTTP_INTERNAL_ERROR) {
LOG.error("Internal Error: {}", err.toXml(), ex);
} else if (LOG.isDebugEnabled()) {
LOG.debug(err.toXml(), ex);
}

Suggested change
LOG.debug("Failed to put acl of Bucket " + bucketName, ex);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will make the change, thanks !!


// BucketEndpoint
private @Metric MutableCounterLong getBucketSuccess;

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will make the change, thanks !!

private @Metric MutableCounterLong getBucketSuccess;

private @Metric MutableCounterLong getBucketFailure;

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will make the change, thanks !!

throw newError(S3ErrorTable.INVALID_BUCKET_NAME, bucketName, exception);
}
LOG.error("Error in Create Bucket Request for bucket: {}", bucketName,
LOG.debug("Error in Create Bucket Request for bucket: {}", bucketName,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: unrelated change.

Suggested change
LOG.debug("Error in Create Bucket Request for bucket: {}", bucketName,
LOG.error("Error in Create Bucket Request for bucket: {}", bucketName,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will make the change, thanks !!

Copy link
Contributor

@adoroszlai adoroszlai left a comment

Choose a reason for hiding this comment

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

Thanks @ArafatKhan2198 for updating the patch, especially for separating the test cases. I noticed one typo where the wrong metric is returned, otherwise it's looks good to me.

Comment on lines 365 to 366
public long getListMultipartUploadsFailure() {
return listMultipartUploadsSuccess.value();
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry, I just noticed this typo:

Suggested change
public long getListMultipartUploadsFailure() {
return listMultipartUploadsSuccess.value();
public long getListMultipartUploadsFailure() {
return listMultipartUploadsFailure.value();

Comment on lines 262 to 270
InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml");

try {
bucketEndpoint.put("unknown_bucket", ACL_MARKER, headers, inputBody);
fail();
} catch (OS3Exception ex) {
}
inputBody.close();
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: using try-with-resources we can ensure that the stream is closed even in case of failure.

Suggested change
InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml");
try {
bucketEndpoint.put("unknown_bucket", ACL_MARKER, headers, inputBody);
fail();
} catch (OS3Exception ex) {
}
inputBody.close();
try (InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml")) {
bucketEndpoint.put("unknown_bucket", ACL_MARKER, headers, inputBody);
fail();
} catch (OS3Exception ex) {
}

// Failing the putACL endpoint by applying ACL on a non-Existent Bucket
long oriMetric = metrics.getPutAclFailure();

clientStub.getObjectStore().createS3Bucket("b1");
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: b1 bucket is not needed for this test case.

Comment on lines +247 to +251
InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml");

bucketEndpoint.put("b1", ACL_MARKER, headers, inputBody);
inputBody.close();
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: using try-with-resources we can ensure that the stream is closed even in case of failure.

Suggested change
InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml");
bucketEndpoint.put("b1", ACL_MARKER, headers, inputBody);
inputBody.close();
try (InputStream inputBody = TestBucketAcl.class.getClassLoader()
.getResourceAsStream("userAccessControlList.xml")) {
bucketEndpoint.put("b1", ACL_MARKER, headers, inputBody);
}

@jojochuang jojochuang merged commit de0b1f9 into apache:master Apr 12, 2022
@ArafatKhan2198 ArafatKhan2198 deleted the HDDS-6528 branch April 12, 2022 09:59
@ArafatKhan2198 ArafatKhan2198 restored the HDDS-6528 branch April 12, 2022 18:57
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.

3 participants