This is an automated email from the ASF dual-hosted git repository.
Gargi-jais11 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 6ff162abdd5 HDDS-15283. GetObjectTagging should return TagSet in
sorted order of key (#10277).
6ff162abdd5 is described below
commit 6ff162abdd591ebb9143cfabbec5f41ac276a812
Author: Gargi Jaiswal <[email protected]>
AuthorDate: Mon May 18 10:00:06 2026 +0530
HDDS-15283. GetObjectTagging should return TagSet in sorted order of key
(#10277).
---
.../ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java | 23 ++++++++++++++++++
.../ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java | 23 ++++++++++++++++++
.../apache/hadoop/ozone/s3/endpoint/S3Tagging.java | 8 +++----
.../ozone/s3/endpoint/TestObjectTaggingGet.java | 27 ++++++++++++++++++----
4 files changed, 72 insertions(+), 9 deletions(-)
diff --git
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
index 8e79e057c03..f1c47df8557 100644
---
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
+++
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v1/AbstractS3SDKV1Tests.java
@@ -47,6 +47,8 @@
import com.amazonaws.services.s3.model.CreateBucketRequest;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.GetObjectRequest;
+import com.amazonaws.services.s3.model.GetObjectTaggingRequest;
+import com.amazonaws.services.s3.model.GetObjectTaggingResult;
import com.amazonaws.services.s3.model.Grantee;
import com.amazonaws.services.s3.model.InitiateMultipartUploadRequest;
import com.amazonaws.services.s3.model.InitiateMultipartUploadResult;
@@ -1125,6 +1127,27 @@ public void testHeadObjectReturnsTaggingCount() {
assertEquals(tags.size(), Integer.parseInt(tagCountHeader.toString()));
}
+ @Test
+ public void testGetObjectTaggingReturnsTagsSortedByKey() {
+ final String bucketName = getBucketName();
+ final String keyName = getKeyName();
+ s3Client.createBucket(bucketName);
+ s3Client.putObject(bucketName, keyName, "");
+
+ List<Tag> tagsPutOrder = Arrays.asList(new Tag("key2", "val2"), new
Tag("key", "val"));
+ s3Client.setObjectTagging(
+ new SetObjectTaggingRequest(bucketName, keyName, new
ObjectTagging(tagsPutOrder)));
+
+ GetObjectTaggingResult taggingResult =
+ s3Client.getObjectTagging(new GetObjectTaggingRequest(bucketName,
keyName));
+ List<Tag> tagSet = taggingResult.getTagSet();
+ assertEquals(2, tagSet.size());
+ assertEquals("key", tagSet.get(0).getKey());
+ assertEquals("val", tagSet.get(0).getValue());
+ assertEquals("key2", tagSet.get(1).getKey());
+ assertEquals("val2", tagSet.get(1).getValue());
+ }
+
@Test
public void testGetObjectWithoutETag() throws Exception {
// Object uploaded using other protocols (e.g. ofs / ozone cli) will not
diff --git
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
index ea608437361..7b12bc6f4dd 100644
---
a/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
+++
b/hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java
@@ -120,6 +120,7 @@
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
import software.amazon.awssdk.services.s3.model.GetObjectTaggingRequest;
+import software.amazon.awssdk.services.s3.model.GetObjectTaggingResponse;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
@@ -243,6 +244,28 @@ public void testPutObject() {
assertEquals("\"37b51d194a7513e45b56f6524f2d51f2\"",
getObjectResponse.eTag());
}
+ @Test
+ public void testGetObjectTaggingReturnsTagsSortedByKey() {
+ final String bucketName = getBucketName();
+ final String keyName = getKeyName();
+ s3Client.createBucket(b -> b.bucket(bucketName));
+ s3Client.putObject(b -> b.bucket(bucketName).key(keyName),
RequestBody.empty());
+
+ List<Tag> tagsPutOrder = Arrays.asList(
+ Tag.builder().key("key2").value("val2").build(),
+ Tag.builder().key("key").value("val").build());
+ s3Client.putObjectTagging(b -> b.bucket(bucketName).key(keyName)
+ .tagging(Tagging.builder().tagSet(tagsPutOrder).build()));
+
+ GetObjectTaggingResponse taggingResult = s3Client.getObjectTagging(b ->
b.bucket(bucketName).key(keyName));
+ List<Tag> tagSet = taggingResult.tagSet();
+ assertEquals(2, tagSet.size());
+ assertEquals("key", tagSet.get(0).key());
+ assertEquals("val", tagSet.get(0).value());
+ assertEquals("key2", tagSet.get(1).key());
+ assertEquals("val2", tagSet.get(1).value());
+ }
+
@Test
public void testPutObjectIfNoneMatch() {
final String bucketName = getBucketName();
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Tagging.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Tagging.java
index 91910787017..fd48a7dcfe7 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Tagging.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3Tagging.java
@@ -118,16 +118,16 @@ public void setValue(String value) {
/**
* Creates a S3 tagging instance (xml representation) from a Map retrieved
- * from OM.
+ * from OM. Tags are ordered by key for stable responses,
+ * consistent with AWS S3 {@code GetObjectTagging}.
* @param tagMap Map representing the tags.
* @return {@link S3Tagging}
*/
public static S3Tagging fromMap(Map<String, String> tagMap) {
List<Tag> tags = tagMap.entrySet()
.stream()
- .map(
- tagEntry -> new Tag(tagEntry.getKey(), tagEntry.getValue())
- )
+ .sorted(Map.Entry.comparingByKey())
+ .map(tagEntry -> new Tag(tagEntry.getKey(), tagEntry.getValue()))
.collect(Collectors.toList());
return new S3Tagging(new TagSet(tags));
}
diff --git
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectTaggingGet.java
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectTaggingGet.java
index f1e166a138d..1f0f0d7b471 100644
---
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectTaggingGet.java
+++
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestObjectTaggingGet.java
@@ -31,6 +31,7 @@
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
+import java.util.List;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import org.apache.hadoop.ozone.client.OzoneClient;
@@ -50,6 +51,7 @@ public class TestObjectTaggingGet {
private static final String BUCKET_NAME = "b1";
private static final String KEY_WITH_TAG = "keyWithTag";
private ObjectEndpoint rest;
+ private HttpHeaders headers;
@BeforeEach
public void init() throws Exception {
@@ -57,7 +59,7 @@ public void init() throws Exception {
OzoneClient client = new OzoneClientStub();
client.getObjectStore().createS3Bucket(BUCKET_NAME);
- HttpHeaders headers = Mockito.mock(HttpHeaders.class);
+ headers = Mockito.mock(HttpHeaders.class);
Mockito.when(headers.getHeaderString(X_AMZ_CONTENT_SHA256))
.thenReturn("UNSIGNED-PAYLOAD");
@@ -65,14 +67,13 @@ public void init() throws Exception {
.setClient(client)
.setHeaders(headers)
.build();
-
- // Create a key with object tags
-
Mockito.when(headers.getHeaderString(TAG_HEADER)).thenReturn("tag1=value1&tag2=value2");
- assertSucceeds(() -> put(rest, BUCKET_NAME, KEY_WITH_TAG, CONTENT));
}
@Test
public void testGetTagging() throws IOException, OS3Exception {
+
Mockito.when(headers.getHeaderString(TAG_HEADER)).thenReturn("tag1=value1&tag2=value2");
+ assertSucceeds(() -> put(rest, BUCKET_NAME, KEY_WITH_TAG, CONTENT));
+
//WHEN
Response response = getTagging(rest, BUCKET_NAME, KEY_WITH_TAG);
@@ -92,6 +93,22 @@ public void testGetTagging() throws IOException,
OS3Exception {
}
}
+ @Test
+ public void testGetTaggingReturnsTagsSortedByKey() throws IOException,
OS3Exception {
+ final String reverseOrderKey = "keyReverseTagOrder";
+
Mockito.when(headers.getHeaderString(TAG_HEADER)).thenReturn("tag2=value2&tag=value");
+ assertSucceeds(() -> put(rest, BUCKET_NAME, reverseOrderKey, CONTENT));
+
+ Response response = getTagging(rest, BUCKET_NAME, reverseOrderKey);
+ assertEquals(HTTP_OK, response.getStatus());
+ List<Tag> tags = ((S3Tagging) response.getEntity()).getTagSet().getTags();
+ assertEquals(2, tags.size());
+ assertEquals("tag", tags.get(0).getKey());
+ assertEquals("value", tags.get(0).getValue());
+ assertEquals("tag2", tags.get(1).getKey());
+ assertEquals("value2", tags.get(1).getValue());
+ }
+
@Test
public void testGetTaggingNoKeyFound() {
assertErrorResponse(NO_SUCH_KEY, () -> getTagging(rest, BUCKET_NAME,
"nonexistent"));
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]