-
Notifications
You must be signed in to change notification settings - Fork 588
HDDS-12870. Fix listObjects corner cases #8307
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
Changes from all commits
6f61f55
365c67b
7bd5677
19f7ba5
f283cc0
5035f36
7611798
228bacd
a4e074d
beffb26
c8d7db3
7e2d5d4
ab8092b
edcb530
93f6cb8
ff1408f
aaf2783
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one or more | ||
| # contributor license agreements. See the NOTICE file distributed with | ||
| # this work for additional information regarding copyright ownership. | ||
| # The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| # (the "License"); you may not use this file except in compliance with | ||
| # the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
|
|
||
| *** Settings *** | ||
| Documentation S3 max-keys validation test for negative and zero values | ||
| Library OperatingSystem | ||
| Library String | ||
| Resource ../commonlib.robot | ||
| Resource commonawslib.robot | ||
| Test Timeout 3 minutes | ||
| Suite Setup Setup s3 tests | ||
|
|
||
| *** Variables *** | ||
| ${ENDPOINT_URL} http://s3g:9878 | ||
| ${BUCKET} generated | ||
|
|
||
| *** Keywords *** | ||
| Prepare Many Objects In Bucket | ||
| [Arguments] ${count}=1100 | ||
| Execute mkdir -p /tmp/manyfiles | ||
| FOR ${i} IN RANGE ${count} | ||
| Execute echo "test-${i}" > /tmp/manyfiles/obj-${i} | ||
| END | ||
| Execute aws s3 cp /tmp/manyfiles s3://${BUCKET}/ --recursive --endpoint-url=${ENDPOINT_URL} | ||
|
|
||
| *** Test Cases *** | ||
|
|
||
| List objects with negative max-keys should fail | ||
| ${result} = Execute AWSS3APICli and checkrc list-objects-v2 --bucket ${BUCKET} --max-keys -1 255 | ||
| Should Contain ${result} InvalidArgument | ||
|
|
||
| List objects with zero max-keys should fail | ||
| ${result} = Execute AWSS3APICli and checkrc list-objects-v2 --bucket ${BUCKET} --max-keys 0 255 | ||
| Should Contain ${result} InvalidArgument | ||
|
|
||
| List objects with max-keys exceeding config limit should not return more than limit | ||
| Prepare Many Objects In Bucket 1100 | ||
| ${result}= Execute AWSS3APICli and checkrc list-objects-v2 --bucket ${BUCKET} --max-keys 9999 --endpoint-url=${ENDPOINT_URL} --output json 0 | ||
| ${tmpfile}= Generate Random String 8 | ||
| ${tmpfile}= Set Variable /tmp/result_${tmpfile}.json | ||
| Create File ${tmpfile} ${result} | ||
| ${count}= Execute and checkrc jq -r '.Contents | length' ${tmpfile} 0 | ||
| Should Be True ${count} <= 1000 | ||
| Remove File ${tmpfile} | ||
|
|
||
| List objects with max-keys less than config limit should return correct count | ||
| Prepare Many Objects In Bucket 1100 | ||
| ${result}= Execute AWSS3APICli and checkrc list-objects-v2 --bucket ${BUCKET} --max-keys 500 --endpoint-url=${ENDPOINT_URL} --output json 0 | ||
| ${tmpfile}= Generate Random String 8 | ||
| ${tmpfile}= Set Variable /tmp/result_${tmpfile}.json | ||
| Create File ${tmpfile} ${result} | ||
| ${count}= Execute and checkrc jq -r '.Contents | length' ${tmpfile} 0 | ||
| Should Be True ${count} == 500 | ||
| Remove File ${tmpfile} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one or more | ||
| * contributor license agreements. See the NOTICE file distributed with | ||
| * this work for additional information regarding copyright ownership. | ||
| * The ASF licenses this file to You under the Apache License, Version 2.0 | ||
| * (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hadoop.ozone.s3.endpoint; | ||
|
|
||
| /** | ||
| * Builder for BucketEndpoint in tests. | ||
| */ | ||
| public class BucketEndpointBuilder extends | ||
| EndpointBuilder<BucketEndpoint> { | ||
|
|
||
| public BucketEndpointBuilder() { | ||
| super(BucketEndpoint::new); | ||
| } | ||
|
|
||
| @Override | ||
| public BucketEndpoint build() { | ||
| BucketEndpoint endpoint = super.build(); | ||
| endpoint.setOzoneConfiguration(getConfig()); | ||
|
|
||
| return endpoint; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,7 @@ | |
|
|
||
| package org.apache.hadoop.ozone.s3.endpoint; | ||
|
|
||
| import static org.apache.hadoop.ozone.s3.S3GatewayConfigKeys.OZONE_S3G_LIST_MAX_KEYS_LIMIT; | ||
| import static org.apache.hadoop.ozone.s3.util.S3Consts.ENCODING_TYPE; | ||
| import static org.junit.jupiter.api.Assertions.assertEquals; | ||
| import static org.junit.jupiter.api.Assertions.assertFalse; | ||
|
|
@@ -26,6 +27,8 @@ | |
| import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
|
||
| import java.io.IOException; | ||
| import java.util.stream.IntStream; | ||
| import org.apache.hadoop.hdds.conf.OzoneConfiguration; | ||
| import org.apache.hadoop.ozone.client.OzoneBucket; | ||
| import org.apache.hadoop.ozone.client.OzoneClient; | ||
| import org.apache.hadoop.ozone.client.OzoneClientStub; | ||
|
|
@@ -519,6 +522,61 @@ public void testEncodingTypeException() throws IOException { | |
| assertEquals(S3ErrorTable.INVALID_ARGUMENT.getCode(), e.getCode()); | ||
| } | ||
|
|
||
| @Test | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should add another test case to check if the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@Jimmyweng006 Use setConfig of the builder to set the config with custom lower max key limit, then call
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the advice @peterxcli , I update the PR but local CI will take some time.
The new commit achieves above testing scenario with a lower max key limit, please help have a look later. Thank you. |
||
| public void testListObjectsWithInvalidMaxKeys() throws Exception { | ||
| OzoneClient client = createClientWithKeys("file1"); | ||
| BucketEndpoint bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder() | ||
| .setClient(client) | ||
| .build(); | ||
|
|
||
| // maxKeys < 0 | ||
| OS3Exception e1 = assertThrows(OS3Exception.class, () -> | ||
| bucketEndpoint.get("bucket", null, null, null, -1, null, | ||
| null, null, null, null, null, null, 1000, null) | ||
| ); | ||
| assertEquals(S3ErrorTable.INVALID_ARGUMENT.getCode(), e1.getCode()); | ||
|
|
||
| // maxKeys == 0 | ||
| OS3Exception e2 = assertThrows(OS3Exception.class, () -> | ||
| bucketEndpoint.get("bucket", null, null, null, 0, null, | ||
| null, null, null, null, null, null, 1000, null) | ||
| ); | ||
| assertEquals(S3ErrorTable.INVALID_ARGUMENT.getCode(), e2.getCode()); | ||
| } | ||
|
|
||
| @Test | ||
| public void testListObjectsRespectsConfiguredMaxKeysLimit() throws Exception { | ||
| // Arrange: Create a bucket with 1001 keys | ||
| String[] keys = IntStream.range(0, 1001).mapToObj(i -> "file" + i).toArray(String[]::new); | ||
| OzoneClient client = createClientWithKeys(keys); | ||
|
|
||
| // Arrange: Set the max-keys limit in the configuration | ||
| OzoneConfiguration config = new OzoneConfiguration(); | ||
| final String configuredMaxKeysLimit = "900"; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is ok, but my original thought is just want this to be a very low value, like 10, so we don't need to create too much key in test. |
||
| config.set(OZONE_S3G_LIST_MAX_KEYS_LIMIT, configuredMaxKeysLimit); | ||
|
|
||
| // Arrange: Build and initialize the BucketEndpoint with the config | ||
| BucketEndpoint bucketEndpoint = EndpointBuilder.newBucketEndpointBuilder() | ||
| .setClient(client) | ||
| .setConfig(config) | ||
| .build(); | ||
| bucketEndpoint.init(); | ||
|
|
||
| // Assert: Ensure the config value is correctly set in the endpoint | ||
| assertEquals(configuredMaxKeysLimit, | ||
| bucketEndpoint.getOzoneConfiguration().get(OZONE_S3G_LIST_MAX_KEYS_LIMIT)); | ||
|
|
||
| // Act: Request more keys than the configured max-keys limit | ||
| final int requestedMaxKeys = Integer.parseInt(configuredMaxKeysLimit) + 1; | ||
| ListObjectResponse response = (ListObjectResponse) | ||
| bucketEndpoint.get("b1", null, null, null, requestedMaxKeys, | ||
| null, null, null, null, null, null, null, | ||
| 1000, null).getEntity(); | ||
|
|
||
| // Assert: The number of returned keys should be capped at the configured limit | ||
| assertEquals(Integer.parseInt(configuredMaxKeysLimit), response.getContents().size()); | ||
| } | ||
|
|
||
| private void assertEncodingTypeObject( | ||
| String exceptName, String exceptEncodingType, EncodingTypeObject object) { | ||
| assertEquals(exceptName, object.getName()); | ||
|
|
||
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.
@kerneltime Do you want this config to apply to all "list" related endpoints? If yes, we should adjust the description and apply the max key logic to other endpoints in new jira.
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.
Also, should we check that this config must >= 1000?