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

asf-gitbox-commits pushed a commit to branch 2.1.X
in repository https://gitbox.apache.org/repos/asf/mina.git


The following commit(s) were added to refs/heads/2.1.X by this push:
     new 716411735 Fixed the compression mina-filter
716411735 is described below

commit 716411735ae6842df6ce3349c7360ac6c8ac2a9c
Author: Emmanuel Lécharny <[email protected]>
AuthorDate: Fri Jun 12 11:14:01 2026 +0200

    Fixed the compression mina-filter
---
 mina-filter-compression/pom.xml                    |   4 +-
 .../mina/filter/compression/CompressionFilter.java |   4 +-
 .../filter/compression/CompressionFilterTest.java  | 211 +++++++--------------
 pom.xml                                            |   9 +
 4 files changed, 80 insertions(+), 148 deletions(-)

diff --git a/mina-filter-compression/pom.xml b/mina-filter-compression/pom.xml
index 8a0c9eeca..3e76c01cc 100644
--- a/mina-filter-compression/pom.xml
+++ b/mina-filter-compression/pom.xml
@@ -45,8 +45,8 @@
     </dependency>
 
     <dependency>
-      <groupId>org.easymock</groupId>
-      <artifactId>easymock</artifactId>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
     </dependency>
   </dependencies>
   
diff --git 
a/mina-filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java
 
b/mina-filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java
index f8c08cebb..04a5db152 100644
--- 
a/mina-filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java
+++ 
b/mina-filter-compression/src/main/java/org/apache/mina/filter/compression/CompressionFilter.java
@@ -273,9 +273,9 @@ public class CompressionFilter extends IoFilterAdapter {
             throw new IllegalStateException("Only one " + 
CompressionFilter.class + " is permitted.");
         }
 
-        Zlib deflater = new Zlib(compressionLevel, Zlib.MODE_INFLATER, 
maxDecompressedSize, 
+        Zlib deflater = new Zlib(compressionLevel, Zlib.MODE_DEFLATER, 
maxDecompressedSize,
                 maxDecompressRatio, decompressRatioMinSize);
-        Zlib inflater = new Zlib(compressionLevel, Zlib.MODE_INFLATER, 
maxDecompressedSize, 
+        Zlib inflater = new Zlib(compressionLevel, Zlib.MODE_INFLATER, 
maxDecompressedSize,
                 maxDecompressRatio, decompressRatioMinSize);
 
         IoSession session = parent.getSession();
diff --git 
a/mina-filter-compression/src/test/java/org/apache/mina/filter/compression/CompressionFilterTest.java
 
b/mina-filter-compression/src/test/java/org/apache/mina/filter/compression/CompressionFilterTest.java
index 299d8b335..cadd544de 100644
--- 
a/mina-filter-compression/src/test/java/org/apache/mina/filter/compression/CompressionFilterTest.java
+++ 
b/mina-filter-compression/src/test/java/org/apache/mina/filter/compression/CompressionFilterTest.java
@@ -19,189 +19,112 @@
  */
 package org.apache.mina.filter.compression;
 
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.mina.core.buffer.IoBuffer;
-import org.apache.mina.core.filterchain.IoFilterChain;
 import org.apache.mina.core.filterchain.IoFilter.NextFilter;
+import org.apache.mina.core.filterchain.IoFilterChain;
+import org.apache.mina.core.session.AttributeKey;
 import org.apache.mina.core.session.IoSession;
 import org.apache.mina.core.write.DefaultWriteRequest;
 import org.apache.mina.core.write.WriteRequest;
-import org.easymock.AbstractMatcher;
-import org.easymock.MockControl;
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.ArgumentCaptor;
 
 /**
+ *
  * @author <a href="http://mina.apache.org";>Apache MINA Project</a>
  */
 public class CompressionFilterTest {
-    private MockControl mockSession;
-
-    private MockControl mockNextFilter;
-
-    private MockControl mockIoFilterChain;
-
-    private IoSession session;
-
-    private NextFilter nextFilter;
-
-    private IoFilterChain ioFilterChain;
+    // the sample data to be used for testing
+    private static final String STR_COMPRESS = repeat("The quick brown fox 
jumps over the lazy dog.  ", 25);
 
     private CompressionFilter filter;
 
-    private Zlib deflater;
-
-    private Zlib inflater;
+    private IoSession session;
 
-    private Zlib actualDeflater;
+    private IoFilterChain filterChain;
 
-    private Zlib actualInflater;
+    private NextFilter nextFilter;
 
-    // the sample data to be used for testing
-    String strCompress = "The quick brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  "
-            + "The quick brown fox jumps over the lazy dog.  " + "The quick 
brown fox jumps over the lazy dog.  ";
+    private static String repeat(String value, int count) {
+        StringBuilder builder = new StringBuilder(value.length() * count);
+        for (int i = 0; i < count; i++) {
+            builder.append(value);
+        }
+        return builder.toString();
+    }
 
     @Before
     public void setUp() {
-        // create the necessary mock controls.
-        mockSession = MockControl.createControl(IoSession.class);
-        mockNextFilter = MockControl.createControl(NextFilter.class);
-        mockIoFilterChain = MockControl.createControl(IoFilterChain.class);
-
-        // set the default matcher
-        mockNextFilter.setDefaultMatcher(new DataMatcher());
-
-        session = (IoSession) mockSession.getMock();
-        nextFilter = (NextFilter) mockNextFilter.getMock();
-        ioFilterChain = (IoFilterChain) mockIoFilterChain.getMock();
-
-        // create an instance of the filter
         filter = new CompressionFilter(CompressionFilter.COMPRESSION_MAX);
 
-        // deflater and inflater that will be used by the filter
-        deflater = new Zlib(Zlib.COMPRESSION_MAX, Zlib.MODE_DEFLATER);
-        inflater = new Zlib(Zlib.COMPRESSION_MAX, Zlib.MODE_INFLATER);
-
-        // create instances of the deflater and inflater to help test the 
output
-        actualDeflater = new Zlib(Zlib.COMPRESSION_MAX, Zlib.MODE_DEFLATER);
-        actualInflater = new Zlib(Zlib.COMPRESSION_MAX, Zlib.MODE_INFLATER);
+        // a mock session whose attributes are stored in a real map, so that 
the deflater and inflater
+        // created by onPreAdd() are actually retrieved by filterWrite() and 
messageReceived().
+        session = mock(IoSession.class);
+        final Map<Object, Object> attributes = new HashMap<>();
+        when(session.setAttribute(any(), any()))
+                .thenAnswer(invocation -> 
attributes.put(invocation.getArgument(0), invocation.getArgument(1)));
+        when(session.getAttribute(any())).thenAnswer(invocation -> 
attributes.get(invocation.getArgument(0)));
+        when(session.containsAttribute(any())).thenAnswer(invocation -> 
attributes.containsKey(invocation.getArgument(0)));
+        when(session.removeAttribute(any())).thenAnswer(invocation -> 
attributes.remove(invocation.getArgument(0)));
+
+        filterChain = mock(IoFilterChain.class);
+        when(filterChain.contains(CompressionFilter.class)).thenReturn(false);
+        when(filterChain.getSession()).thenReturn(session);
+
+        nextFilter = mock(NextFilter.class);
     }
 
     @Test
-    public void testCompression() throws Exception {
-        // prepare the input data
-        IoBuffer buf = 
IoBuffer.wrap(strCompress.getBytes(StandardCharsets.UTF_8));
-        IoBuffer actualOutput = actualDeflater.deflate(buf);
-        buf.flip();
-        WriteRequest writeRequest = new DefaultWriteRequest(buf);
-
-        // record all the mock calls
-        ioFilterChain.contains(CompressionFilter.class);
-        mockIoFilterChain.setReturnValue(false);
+    public void testCompressionRoundTrip() throws Exception {
+        filter.onPreAdd(filterChain, "CompressionFilter", nextFilter);
 
-        ioFilterChain.getSession();
-        mockIoFilterChain.setReturnValue(session);
-
-        session.setAttribute(CompressionFilter.class.getName() + ".Deflater", 
deflater);
-        mockSession.setDefaultMatcher(new DataMatcher());
-        mockSession.setReturnValue(null, MockControl.ONE);
-
-        session.setAttribute(CompressionFilter.class.getName() + ".Inflater", 
inflater);
-        mockSession.setReturnValue(null, MockControl.ONE);
-
-        session.containsAttribute(CompressionFilter.DISABLE_COMPRESSION_ONCE);
-        mockSession.setReturnValue(false);
-
-        session.getAttribute(CompressionFilter.class.getName() + ".Deflater");
-        mockSession.setReturnValue(deflater);
-
-        nextFilter.filterWrite(session, new DefaultWriteRequest(actualOutput));
-
-        // switch to playback mode
-        mockSession.replay();
-        mockIoFilterChain.replay();
-        mockNextFilter.replay();
-
-        // make the actual calls on the filter
-        filter.onPreAdd(ioFilterChain, "CompressionFilter", nextFilter);
+        IoBuffer input = 
IoBuffer.wrap(STR_COMPRESS.getBytes(StandardCharsets.UTF_8));
+        WriteRequest writeRequest = new DefaultWriteRequest(input);
         filter.filterWrite(nextFilter, session, writeRequest);
 
-        // verify that all the calls happened as recorded
-        mockNextFilter.verify();
+        // capture the compressed buffer forwarded down the chain
+        ArgumentCaptor<WriteRequest> writeCaptor = 
ArgumentCaptor.forClass(WriteRequest.class);
+        verify(nextFilter).filterWrite(eq(session), writeCaptor.capture());
+        IoBuffer compressed = (IoBuffer) writeCaptor.getValue().getMessage();
+
+        // feeding the compressed buffer back in must reproduce the original 
payload
+        filter.messageReceived(nextFilter, session, compressed);
+        ArgumentCaptor<Object> receiveCaptor = 
ArgumentCaptor.forClass(Object.class);
+        verify(nextFilter).messageReceived(eq(session), 
receiveCaptor.capture());
+        IoBuffer decompressed = (IoBuffer) receiveCaptor.getValue();
 
-        assertTrue(true);
+        assertEquals(STR_COMPRESS, 
decompressed.getString(StandardCharsets.UTF_8.newDecoder()));
     }
 
+    /**
+     * Regression guard: onPreAdd() must register the deflater in deflate mode 
and the inflater in
+     * inflate mode, not the other way round. Verified by checking each 
rejects the opposite operation.
+     */
     @Test
-    public void testDecompression() throws Exception {
-        // prepare the input data
-        IoBuffer buf = 
IoBuffer.wrap(strCompress.getBytes(StandardCharsets.UTF_8));
-        IoBuffer byteInput = actualDeflater.deflate(buf);
-        IoBuffer actualOutput = actualInflater.inflate(byteInput);
-
-        // record all the mock calls
-        ioFilterChain.contains(CompressionFilter.class);
-        mockIoFilterChain.setReturnValue(false);
+    public void testDeflaterAndInflaterNotSwapped() throws Exception {
+        filter.onPreAdd(filterChain, "CompressionFilter", nextFilter);
 
-        ioFilterChain.getSession();
-        mockIoFilterChain.setReturnValue(session);
+        IoBuffer input = 
IoBuffer.wrap(STR_COMPRESS.getBytes(StandardCharsets.UTF_8));
 
-        session.setAttribute(CompressionFilter.class.getName() + ".Deflater", 
deflater);
-        mockSession.setDefaultMatcher(new DataMatcher());
-        mockSession.setReturnValue(null, MockControl.ONE);
+        Zlib deflater = (Zlib) session.getAttribute(new 
AttributeKey(CompressionFilter.class, "deflater"));
+        assertNotNull(deflater);
+        assertThrows(IllegalStateException.class, () -> 
deflater.inflate(input));
 
-        session.setAttribute(CompressionFilter.class.getName() + ".Inflater", 
inflater);
-        mockSession.setReturnValue(null, MockControl.ONE);
 
-        session.getAttribute(CompressionFilter.class.getName() + ".Inflater");
-        mockSession.setReturnValue(inflater);
-
-        nextFilter.messageReceived(session, actualOutput);
-
-        // switch to playback mode
-        mockSession.replay();
-        mockIoFilterChain.replay();
-        mockNextFilter.replay();
-
-        // make the actual calls on the filter
-        filter.onPreAdd(ioFilterChain, "CompressionFilter", nextFilter);
-        filter.messageReceived(nextFilter, session, byteInput);
-
-        // verify that all the calls happened as recorded
-        mockNextFilter.verify();
-
-        assertTrue(true);
-    }
-
-    /**
-     * A matcher used to check if the actual and expected outputs matched
-     */
-    class DataMatcher extends AbstractMatcher {
-        @Override
-        protected boolean argumentMatches(Object arg0, Object arg1) {
-            // we need to only verify the ByteBuffer output
-            if (arg0 instanceof WriteRequest) {
-                WriteRequest expected = (WriteRequest) arg0;
-                WriteRequest actual = (WriteRequest) arg1;
-                IoBuffer bExpected = (IoBuffer) expected.getMessage();
-                IoBuffer bActual = (IoBuffer) actual.getMessage();
-                return bExpected.equals(bActual);
-            }
-            return true;
-        }
+        Zlib inflater = (Zlib) session.getAttribute(new 
AttributeKey(CompressionFilter.class, "inflater"));
+        assertNotNull(inflater);
+        assertThrows(IllegalStateException.class, () -> 
inflater.deflate(input));
     }
 }
diff --git a/pom.xml b/pom.xml
index 293a8fd47..95126fed6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -149,6 +149,7 @@
     <version.junit>4.13.2</version.junit>
     <version.jzlib>1.1.3</version.jzlib>
     <version.log4j>1.2.17</version.log4j>
+    <version.mockito>4.11.0</version.mockito>
     <!-- DO NOT CHANGE. Breaks the build with more recent versions -->
     <version.ognl>3.3.4</version.ognl>
     <version.pmd>7.24.0</version.pmd>
@@ -299,6 +300,14 @@
         <scope>test</scope>
       </dependency>
 
+      <dependency>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-core</artifactId>
+        <version>${version.mockito}</version>
+        <optional>true</optional>
+        <scope>test</scope>
+      </dependency>
+
       <dependency>
         <groupId>net.sourceforge.pmd</groupId>
         <artifactId>pmd-core</artifactId>

Reply via email to