This is an automated email from the ASF dual-hosted git repository.

adoroszlai 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 2930ecc69c5 HDDS-10791. Duplicated instanceof checks in 
OzoneOutputStream (#9370)
2930ecc69c5 is described below

commit 2930ecc69c556111cb312c349f9999f3251873ef
Author: Russole <[email protected]>
AuthorDate: Tue Dec 2 03:59:05 2025 +0800

    HDDS-10791. Duplicated instanceof checks in OzoneOutputStream (#9370)
---
 .../hadoop/ozone/client/io/OzoneOutputStream.java  |  42 +++---
 .../ozone/client/io/TestOzoneOutputStream.java     | 152 +++++++++++++++++++++
 2 files changed, 169 insertions(+), 25 deletions(-)

diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
index f31b56ca423..c0e14b089ef 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
@@ -139,36 +139,28 @@ public OmMultipartCommitUploadPartInfo 
getCommitUploadPartInfo() {
   public OutputStream getOutputStream() {
     return outputStream;
   }
-
+  
   public KeyOutputStream getKeyOutputStream() {
-    if (outputStream instanceof KeyOutputStream) {
-      return ((KeyOutputStream) outputStream);
-    } else  if (outputStream instanceof CryptoOutputStream) {
-      OutputStream wrappedStream =
-          ((CryptoOutputStream) outputStream).getWrappedStream();
-      if (wrappedStream instanceof KeyOutputStream) {
-        return ((KeyOutputStream) wrappedStream);
-      }
-    } else if (outputStream instanceof CipherOutputStreamOzone) {
-      OutputStream wrappedStream =
-          ((CipherOutputStreamOzone) outputStream).getWrappedStream();
-      if (wrappedStream instanceof KeyOutputStream) {
-        return ((KeyOutputStream)wrappedStream);
-      }
-    }
-    // Otherwise return null.
-    return null;
+    OutputStream base = unwrap(outputStream);
+    return base instanceof KeyOutputStream ? (KeyOutputStream) base : null;
   }
 
   @Override
   public Map<String, String> getMetadata() {
-    if (outputStream instanceof CryptoOutputStream) {
-      return ((KeyMetadataAware)((CryptoOutputStream) outputStream)
-          .getWrappedStream()).getMetadata();
-    } else if (outputStream instanceof CipherOutputStreamOzone) {
-      return ((KeyMetadataAware)((CipherOutputStreamOzone) outputStream)
-          .getWrappedStream()).getMetadata();
+    OutputStream base = unwrap(outputStream);
+    if (base instanceof KeyMetadataAware) {
+      return ((KeyMetadataAware) base).getMetadata();
+    }
+    throw new IllegalStateException(
+        "OutputStream is not KeyMetadataAware: " + base.getClass());
+  }
+
+  private static OutputStream unwrap(OutputStream out) {
+    if (out instanceof CryptoOutputStream) {
+      return ((CryptoOutputStream) out).getWrappedStream();
+    } else if (out instanceof CipherOutputStreamOzone) {
+      return ((CipherOutputStreamOzone) out).getWrappedStream();
     }
-    return ((KeyMetadataAware) outputStream).getMetadata();
+    return out;
   }
 }
diff --git 
a/hadoop-ozone/client/src/test/java/org/apache/hadoop/ozone/client/io/TestOzoneOutputStream.java
 
b/hadoop-ozone/client/src/test/java/org/apache/hadoop/ozone/client/io/TestOzoneOutputStream.java
new file mode 100644
index 00000000000..d6a906582f4
--- /dev/null
+++ 
b/hadoop-ozone/client/src/test/java/org/apache/hadoop/ozone/client/io/TestOzoneOutputStream.java
@@ -0,0 +1,152 @@
+/*
+ * 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.client.io;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.hadoop.crypto.CryptoOutputStream;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for OzoneOutputStream covering metadata and unwrap behavior.
+ */
+public class TestOzoneOutputStream {
+
+  /**
+   * Fake KeyOutputStream implementation for testing.
+   * Uses the package-private KeyOutputStream() constructor.
+   */
+  private static class FakeKeyOutputStream extends KeyOutputStream
+      implements KeyMetadataAware {
+
+    private final Map<String, String> metadata;
+
+    FakeKeyOutputStream(Map<String, String> metadata) {
+      super(); // VisibleForTesting constructor
+      this.metadata = metadata;
+    }
+
+    @Override
+    public Map<String, String> getMetadata() {
+      return metadata;
+    }
+
+    @Override
+    public void flush() {
+      // avoid KeyOutputStream.flush() using null semaphore
+    }
+
+    @Override
+    public void close() {
+      // avoid real close logic touching internal state
+    }
+  }
+
+  /**
+   * Minimal fake CipherOutputStreamOzone wrapper for testing unwrap().
+   */
+  private static class FakeCipherOutputStreamOzone
+      extends CipherOutputStreamOzone {
+
+    FakeCipherOutputStreamOzone(OutputStream out) {
+      super(out);
+    }
+
+    @Override
+    public OutputStream getWrappedStream() {
+      return super.getWrappedStream();
+    }
+  }
+
+  /**
+   * test Plain KeyOutputStream and getMetadata() (no encryption).
+   */
+  @Test
+  public void testPlainKeyOutputStream() throws IOException {
+    Map<String, String> metadata = Collections.singletonMap("k1", "v1");
+
+    FakeKeyOutputStream key = new FakeKeyOutputStream(metadata);
+    try (OzoneOutputStream ozone = new OzoneOutputStream(key, null)) {
+      assertNotNull(ozone.getKeyOutputStream());
+      assertEquals("v1", ozone.getMetadata().get("k1"));
+    }
+  }
+
+  /**
+   * test getKeyOutputStream and getMetadata() wrapped inside 
CryptoOutputStream.
+   */
+  @Test
+  public void testCryptoWrapped() throws IOException {
+    Map<String, String> metadata = Collections.singletonMap("k1", "v1");
+
+    FakeKeyOutputStream key = new FakeKeyOutputStream(metadata);
+
+    // Mockito mock for CryptoOutputStream: we only care that
+    // 1) it is an instance of CryptoOutputStream
+    // 2) getWrappedStream() returns the underlying KeyOutputStream
+    CryptoOutputStream crypto = mock(CryptoOutputStream.class);
+    when(crypto.getWrappedStream()).thenReturn(key);
+
+    try (OzoneOutputStream ozone = new OzoneOutputStream(crypto, null)) {
+      assertNotNull(ozone.getKeyOutputStream());
+      assertEquals("v1", ozone.getMetadata().get("k1"));
+    }
+  }
+
+  /**
+   * test getKeyOutputStream and getMetadata() wrapped inside 
CipherOutputStreamOzone.
+   */
+  @Test
+  public void testCipherWrapped() throws IOException {
+    Map<String, String> metadata = Collections.singletonMap("k1", "v1");
+
+    FakeKeyOutputStream key = new FakeKeyOutputStream(metadata);
+    FakeCipherOutputStreamOzone cipher =
+        new FakeCipherOutputStreamOzone(key);
+
+    try (OzoneOutputStream ozone = new OzoneOutputStream(cipher, null)) {
+      assertNotNull(ozone.getKeyOutputStream());
+      assertEquals("v1", ozone.getMetadata().get("k1"));
+    }
+  }
+
+  /**
+   * test for Non-KeyMetadataAware stream verify that exception is thrown here.
+   */
+  @Test
+  public void testNonKeyMetadataAwareThrows() throws IOException {
+    OutputStream nonMeta = new OutputStream() {
+      @Override
+      public void write(int b) {
+
+      }
+    };
+
+    try (OzoneOutputStream ozone = new OzoneOutputStream(nonMeta, null)) {
+      assertThrows(IllegalStateException.class, ozone::getMetadata);
+    }
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to