You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by zh...@apache.org on 2025/10/08 13:11:58 UTC

(hbase) branch branch-2.6 updated: HBASE-29614 Remove static final field modification in tests around Unsafe (#7337) (#7347)

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

zhangduo pushed a commit to branch branch-2.6
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2.6 by this push:
     new 6b887db4937 HBASE-29614 Remove static final field modification in tests around Unsafe (#7337) (#7347)
6b887db4937 is described below

commit 6b887db493796fd5c9c2bcd3c900186e22694488
Author: Duo Zhang <zh...@apache.org>
AuthorDate: Wed Oct 8 20:46:48 2025 +0800

    HBASE-29614 Remove static final field modification in tests around Unsafe (#7337) (#7347)
    
    Signed-off-by: Peng Lu <lu...@apache.org>
    (cherry picked from commit e0cec314c839158eac7dbd080582ebce83718a0b)
---
 hbase-common/pom.xml                               |    5 +
 ...fferUtils.java => ByteBufferUtilsTestBase.java} |  184 +--
 .../util/{TestBytes.java => BytesTestBase.java}    |  177 +--
 .../hadoop/hbase/util/TestByteBufferUtils.java     |  652 +----------
 .../hbase/util/TestByteBufferUtilsWoUnsafe.java    |   43 +
 .../org/apache/hadoop/hbase/util/TestBytes.java    |  613 +---------
 .../hadoop/hbase/util/TestBytesWoUnsafe.java       |   41 +
 hbase-server/pom.xml                               |    5 +
 .../hadoop/hbase/TestHBaseTestingUtility.java      |   37 -
 .../org/apache/hadoop/hbase/TestPortAllocator.java |   67 ++
 ...ientSide3.java => FromClientSide3TestBase.java} |  135 +--
 .../hadoop/hbase/client/TestFromClientSide3.java   | 1208 +-------------------
 .../hbase/client/TestScannersFromClientSide.java   |    2 +-
 .../hbase/ipc/TestProtobufRpcServiceImpl.java      |   66 +-
 .../hbase/security/access/TestRpcAccessChecks.java |   45 +-
 .../hbase/util/TestFromClientSide3WoUnsafe.java    |   42 +-
 16 files changed, 486 insertions(+), 2836 deletions(-)

diff --git a/hbase-common/pom.xml b/hbase-common/pom.xml
index 9222eca81b6..dd0c3317087 100644
--- a/hbase-common/pom.xml
+++ b/hbase-common/pom.xml
@@ -145,6 +145,11 @@
       <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-inline</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>jcl-over-slf4j</artifactId>
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/ByteBufferUtilsTestBase.java
similarity index 85%
copy from hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java
copy to hbase-common/src/test/java/org/apache/hadoop/hbase/util/ByteBufferUtilsTestBase.java
index 8f180d266c2..19491547577 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/ByteBufferUtilsTestBase.java
@@ -17,18 +17,16 @@
  */
 package org.apache.hadoop.hbase.util;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -43,92 +41,48 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.HBaseCommonTestingUtility;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.nio.ByteBuff;
-import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.testclassification.MiscTests;
-import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
 import org.apache.hadoop.io.WritableUtils;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@Category({ MiscTests.class, MediumTests.class })
-@RunWith(Parameterized.class)
-public class TestByteBufferUtils {
-
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE =
-    HBaseClassTestRule.forClass(TestByteBufferUtils.class);
-
-  private static final String UNSAFE_AVAIL_NAME = "UNSAFE_AVAIL";
-  private static final String UNSAFE_UNALIGNED_NAME = "UNSAFE_UNALIGNED";
-  private byte[] array;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-  @AfterClass
-  public static void afterClass() throws Exception {
-    detectAvailabilityOfUnsafe();
-  }
+public class ByteBufferUtilsTestBase {
 
-  @Parameterized.Parameters
-  public static Collection<Object[]> parameters() {
-    return HBaseCommonTestingUtility.BOOLEAN_PARAMETERIZED;
-  }
+  private static final Logger LOG = LoggerFactory.getLogger(ByteBufferUtilsTestBase.class);
 
-  private static void setUnsafe(String fieldName, boolean value) throws Exception {
-    Field field = ByteBufferUtils.class.getDeclaredField(fieldName);
-    field.setAccessible(true);
-    Field modifiersField = ReflectionUtils.getModifiersField();
-    modifiersField.setAccessible(true);
-    int oldModifiers = field.getModifiers();
-    modifiersField.setInt(field, oldModifiers & ~Modifier.FINAL);
-    try {
-      field.set(null, value);
-    } finally {
-      modifiersField.setInt(field, oldModifiers);
-    }
-  }
+  private static int MAX_VLONG_LENGTH = 9;
+  private static Collection<Long> testNumbers;
 
-  static void disableUnsafe() throws Exception {
-    if (ByteBufferUtils.UNSAFE_AVAIL) {
-      setUnsafe(UNSAFE_AVAIL_NAME, false);
-    }
-    if (ByteBufferUtils.UNSAFE_UNALIGNED) {
-      setUnsafe(UNSAFE_UNALIGNED_NAME, false);
-    }
-    assertFalse(ByteBufferUtils.UNSAFE_AVAIL);
-    assertFalse(ByteBufferUtils.UNSAFE_UNALIGNED);
-  }
+  private byte[] array;
 
-  static void detectAvailabilityOfUnsafe() throws Exception {
-    if (ByteBufferUtils.UNSAFE_AVAIL != HBasePlatformDependent.isUnsafeAvailable()) {
-      setUnsafe(UNSAFE_AVAIL_NAME, HBasePlatformDependent.isUnsafeAvailable());
-    }
-    if (ByteBufferUtils.UNSAFE_UNALIGNED != HBasePlatformDependent.unaligned()) {
-      setUnsafe(UNSAFE_UNALIGNED_NAME, HBasePlatformDependent.unaligned());
+  @BeforeAll
+  public static void setUpBeforeAll() {
+    SortedSet<Long> a = new TreeSet<>();
+    for (int i = 0; i <= 63; ++i) {
+      long v = -1L << i;
+      assertTrue(v < 0);
+      addNumber(a, v);
+      v = (1L << i) - 1;
+      assertTrue(v >= 0);
+      addNumber(a, v);
     }
-    assertEquals(ByteBufferUtils.UNSAFE_AVAIL, HBasePlatformDependent.isUnsafeAvailable());
-    assertEquals(ByteBufferUtils.UNSAFE_UNALIGNED, HBasePlatformDependent.unaligned());
-  }
 
-  public TestByteBufferUtils(boolean useUnsafeIfPossible) throws Exception {
-    if (useUnsafeIfPossible) {
-      detectAvailabilityOfUnsafe();
-    } else {
-      disableUnsafe();
-    }
+    testNumbers = Collections.unmodifiableSet(a);
+    LOG.info("Testing variable-length long serialization using: {} (count: {})", testNumbers,
+      testNumbers.size());
+    assertEquals(1753, testNumbers.size());
+    assertEquals(Long.MIN_VALUE, a.first().longValue());
+    assertEquals(Long.MAX_VALUE, a.last().longValue());
   }
 
   /**
    * Create an array with sample data.
    */
-  @Before
+  @BeforeEach
   public void setUp() {
     array = new byte[8];
     for (int i = 0; i < array.length; ++i) {
@@ -136,9 +90,6 @@ public class TestByteBufferUtils {
     }
   }
 
-  private static final int MAX_VLONG_LENGTH = 9;
-  private static final Collection<Long> testNumbers;
-
   private static void addNumber(Set<Long> a, long l) {
     if (l != Long.MIN_VALUE) {
       a.add(l - 1);
@@ -154,25 +105,6 @@ public class TestByteBufferUtils {
     }
   }
 
-  static {
-    SortedSet<Long> a = new TreeSet<>();
-    for (int i = 0; i <= 63; ++i) {
-      long v = -1L << i;
-      assertTrue(v < 0);
-      addNumber(a, v);
-      v = (1L << i) - 1;
-      assertTrue(v >= 0);
-      addNumber(a, v);
-    }
-
-    testNumbers = Collections.unmodifiableSet(a);
-    System.err.println("Testing variable-length long serialization using: " + testNumbers
-      + " (count: " + testNumbers.size() + ")");
-    assertEquals(1753, testNumbers.size());
-    assertEquals(Long.MIN_VALUE, a.first().longValue());
-    assertEquals(Long.MAX_VALUE, a.last().longValue());
-  }
-
   @Test
   public void testReadWriteVLong() {
     for (long l : testNumbers) {
@@ -366,33 +298,6 @@ public class TestByteBufferUtils {
     }
   }
 
-  // Utility methods invoked from test methods
-
-  private void testCompressedInt(int value) throws IOException {
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    ByteBufferUtils.putCompressedInt(bos, value);
-    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
-    int parsedValue = ByteBufferUtils.readCompressedInt(bis);
-    assertEquals(value, parsedValue);
-  }
-
-  private void testPutInt(int value) {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    try {
-      ByteBufferUtils.putInt(baos, value);
-    } catch (IOException e) {
-      throw new RuntimeException("Bug in putIn()", e);
-    }
-
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    DataInputStream dis = new DataInputStream(bais);
-    try {
-      assertEquals(dis.readInt(), value);
-    } catch (IOException e) {
-      throw new RuntimeException("Bug in test!", e);
-    }
-  }
-
   @Test
   public void testToBytes() {
     ByteBuffer buffer = ByteBuffer.allocate(5);
@@ -655,6 +560,32 @@ public class TestByteBufferUtils {
       ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()));
   }
 
+  // Below are utility methods invoked from test methods
+  private static void testCompressedInt(int value) throws IOException {
+    ByteArrayOutputStream bos = new ByteArrayOutputStream();
+    ByteBufferUtils.putCompressedInt(bos, value);
+    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+    int parsedValue = ByteBufferUtils.readCompressedInt(bis);
+    assertEquals(value, parsedValue);
+  }
+
+  private static void testPutInt(int value) {
+    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+    try {
+      ByteBufferUtils.putInt(baos, value);
+    } catch (IOException e) {
+      throw new RuntimeException("Bug in putIn()", e);
+    }
+
+    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+    DataInputStream dis = new DataInputStream(bais);
+    try {
+      assertEquals(dis.readInt(), value);
+    } catch (IOException e) {
+      throw new RuntimeException("Bug in test!", e);
+    }
+  }
+
   private static void fillBB(ByteBuffer bb, byte b) {
     for (int i = bb.position(); i < bb.limit(); i++) {
       bb.put(i, b);
@@ -666,5 +597,4 @@ public class TestByteBufferUtils {
       bb[i] = b;
     }
   }
-
 }
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/BytesTestBase.java
similarity index 77%
copy from hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java
copy to hbase-common/src/test/java/org/apache/hadoop/hbase/util/BytesTestBase.java
index b7434895998..96df8bc3939 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/BytesTestBase.java
@@ -17,21 +17,19 @@
  */
 package org.apache.hadoop.hbase.util;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
 import java.math.BigDecimal;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -39,57 +37,21 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
 import java.util.concurrent.ThreadLocalRandom;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.testclassification.MiscTests;
-import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
 import org.apache.hadoop.io.WritableUtils;
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category({ MiscTests.class, MediumTests.class })
-public class TestBytes {
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestBytes.class);
-
-  private static void setUnsafe(boolean value) throws Exception {
-    Field field = Bytes.class.getDeclaredField("UNSAFE_UNALIGNED");
-    field.setAccessible(true);
-
-    Field modifiersField = ReflectionUtils.getModifiersField();
-    modifiersField.setAccessible(true);
-    int oldModifiers = field.getModifiers();
-    modifiersField.setInt(field, oldModifiers & ~Modifier.FINAL);
-    try {
-      field.set(null, value);
-    } finally {
-      modifiersField.setInt(field, oldModifiers);
-    }
-    assertEquals(Bytes.UNSAFE_UNALIGNED, value);
-  }
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-  @Test
-  public void testShort() throws Exception {
-    testShort(false);
-  }
+public class BytesTestBase {
 
-  @Test
-  public void testShortUnsafe() throws Exception {
-    testShort(true);
-  }
+  private static final Logger LOG = LoggerFactory.getLogger(BytesTestBase.class);
 
-  private static void testShort(boolean unsafe) throws Exception {
-    setUnsafe(unsafe);
-    try {
-      for (short n : Arrays.asList(Short.MIN_VALUE, (short) -100, (short) -1, (short) 0, (short) 1,
-        (short) 300, Short.MAX_VALUE)) {
-        byte[] bytes = Bytes.toBytes(n);
-        assertEquals(Bytes.toShort(bytes, 0, bytes.length), n);
-      }
-    } finally {
-      setUnsafe(HBasePlatformDependent.unaligned());
+  @Test
+  public void testShort() throws Exception {
+    for (short n : Arrays.asList(Short.MIN_VALUE, (short) -100, (short) -1, (short) 0, (short) 1,
+      (short) 300, Short.MAX_VALUE)) {
+      byte[] bytes = Bytes.toBytes(n);
+      assertEquals(Bytes.toShort(bytes, 0, bytes.length), n);
     }
   }
 
@@ -122,7 +84,7 @@ public class TestBytes {
     byte[] highest = Bytes.toBytes("EEE");
     byte[][] parts = Bytes.split(lowest, highest, 1);
     for (byte[] bytes : parts) {
-      System.out.println(Bytes.toString(bytes));
+      LOG.info(Bytes.toString(bytes));
     }
     assertEquals(3, parts.length);
     assertTrue(Bytes.equals(parts[1], middle));
@@ -130,7 +92,7 @@ public class TestBytes {
     highest = Bytes.toBytes("DDD");
     parts = Bytes.split(lowest, highest, 2);
     for (byte[] part : parts) {
-      System.out.println(Bytes.toString(part));
+      LOG.info(Bytes.toString(part));
     }
     assertEquals(4, parts.length);
     // Assert that 3rd part is 'CCC'.
@@ -145,7 +107,7 @@ public class TestBytes {
     byte[] middle = Bytes.toBytes("http://]");
     byte[][] parts = Bytes.split(lowest, highest, 1);
     for (byte[] part : parts) {
-      System.out.println(Bytes.toString(part));
+      LOG.info(Bytes.toString(part));
     }
     assertEquals(3, parts.length);
     assertTrue(Bytes.equals(parts[1], middle));
@@ -168,13 +130,13 @@ public class TestBytes {
     // Single split should work
     byte[][] parts = Bytes.split(low, high, 1);
     for (int i = 0; i < parts.length; i++) {
-      System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
+      LOG.info("" + i + " -> " + Bytes.toStringBinary(parts[i]));
     }
-    assertEquals("Returned split should have 3 parts but has " + parts.length, 3, parts.length);
+    assertEquals(3, parts.length, "Returned split should have 3 parts but has " + parts.length);
 
     // If split more than once, use additional byte to split
     parts = Bytes.split(low, high, 2);
-    assertNotNull("Split with an additional byte", parts);
+    assertNotNull(parts, "Split with an additional byte");
     assertEquals(parts.length, low.length + 1);
 
     // Split 0 times should throw IAE
@@ -478,30 +440,30 @@ public class TestBytes {
   @Test
   public void testUnsignedBinarySearch() {
     byte[] bytes = new byte[] { 0, 5, 123, 127, -128, -100, -1 };
-    Assert.assertEquals(1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 5));
-    Assert.assertEquals(3, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 127));
-    Assert.assertEquals(4, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -128));
-    Assert.assertEquals(5, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -100));
-    Assert.assertEquals(6, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -1));
-    Assert.assertEquals(-1 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 2));
-    Assert.assertEquals(-6 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -5));
+    assertEquals(1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 5));
+    assertEquals(3, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 127));
+    assertEquals(4, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -128));
+    assertEquals(5, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -100));
+    assertEquals(6, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -1));
+    assertEquals(-1 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 2));
+    assertEquals(-6 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -5));
   }
 
   @Test
   public void testUnsignedIncrement() {
     byte[] a = Bytes.toBytes(0);
     int a2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(a), 0);
-    Assert.assertEquals(1, a2);
+    assertEquals(1, a2);
 
     byte[] b = Bytes.toBytes(-1);
     byte[] actual = Bytes.unsignedCopyAndIncrement(b);
-    Assert.assertNotSame(b, actual);
+    assertNotSame(b, actual);
     byte[] expected = new byte[] { 1, 0, 0, 0, 0 };
     assertArrayEquals(expected, actual);
 
     byte[] c = Bytes.toBytes(255);// should wrap to the next significant byte
     int c2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(c), 0);
-    Assert.assertEquals(256, c2);
+    assertEquals(256, c2);
   }
 
   @Test
@@ -552,7 +514,7 @@ public class TestBytes {
       Bytes.putByteBuffer(b, i, ByteBuffer.wrap(new byte[] { i }));
     }
     for (byte i = 0; i < 100; i++) {
-      Assert.assertEquals(i, b[i]);
+      assertEquals(i, b[i]);
     }
   }
 
@@ -563,9 +525,9 @@ public class TestBytes {
       "0123456789abcdef", "283462839463924623984692834692346ABCDFEDDCA0"));
     for (String testString : testStrings) {
       byte[] byteData = Bytes.fromHex(testString);
-      Assert.assertEquals(testString.length() / 2, byteData.length);
+      assertEquals(testString.length() / 2, byteData.length);
       String result = Bytes.toHex(byteData);
-      Assert.assertTrue(testString.equalsIgnoreCase(result));
+      assertTrue(testString.equalsIgnoreCase(result));
     }
 
     List<byte[]> testByteData = new ArrayList<>(5);
@@ -580,7 +542,7 @@ public class TestBytes {
 
     for (byte[] testData : testByteData) {
       String hexString = Bytes.toHex(testData);
-      Assert.assertEquals(testData.length * 2, hexString.length());
+      assertEquals(testData.length * 2, hexString.length());
       byte[] result = Bytes.fromHex(hexString);
       assertArrayEquals(testData, result);
     }
@@ -588,44 +550,29 @@ public class TestBytes {
 
   @Test
   public void testFindCommonPrefix() throws Exception {
-    testFindCommonPrefix(false);
-  }
-
-  @Test
-  public void testFindCommonPrefixUnsafe() throws Exception {
-    testFindCommonPrefix(true);
-  }
-
-  private static void testFindCommonPrefix(boolean unsafe) throws Exception {
-    setUnsafe(unsafe);
-    try {
-      // tests for common prefixes less than 8 bytes in length (i.e. using non-vectorized path)
-      byte[] hello = Bytes.toBytes("hello");
-      byte[] helloWorld = Bytes.toBytes("helloworld");
-
-      assertEquals(5,
-        Bytes.findCommonPrefix(hello, helloWorld, hello.length, helloWorld.length, 0, 0));
-      assertEquals(5, Bytes.findCommonPrefix(hello, hello, hello.length, hello.length, 0, 0));
-      assertEquals(3,
-        Bytes.findCommonPrefix(hello, hello, hello.length - 2, hello.length - 2, 2, 2));
-      assertEquals(0, Bytes.findCommonPrefix(hello, hello, 0, 0, 0, 0));
-
-      // tests for common prefixes greater than 8 bytes in length which may use the vectorized path
-      byte[] hellohello = Bytes.toBytes("hellohello");
-      byte[] hellohellohi = Bytes.toBytes("hellohellohi");
-
-      assertEquals(10, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
-        hellohellohi.length, 0, 0));
-      assertEquals(10, Bytes.findCommonPrefix(hellohellohi, hellohello, hellohellohi.length,
-        hellohello.length, 0, 0));
-      assertEquals(10,
-        Bytes.findCommonPrefix(hellohello, hellohello, hellohello.length, hellohello.length, 0, 0));
-
-      hellohello[2] = 0;
-      assertEquals(2, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
-        hellohellohi.length, 0, 0));
-    } finally {
-      setUnsafe(HBasePlatformDependent.unaligned());
-    }
+    // tests for common prefixes less than 8 bytes in length (i.e. using non-vectorized path)
+    byte[] hello = Bytes.toBytes("hello");
+    byte[] helloWorld = Bytes.toBytes("helloworld");
+
+    assertEquals(5,
+      Bytes.findCommonPrefix(hello, helloWorld, hello.length, helloWorld.length, 0, 0));
+    assertEquals(5, Bytes.findCommonPrefix(hello, hello, hello.length, hello.length, 0, 0));
+    assertEquals(3, Bytes.findCommonPrefix(hello, hello, hello.length - 2, hello.length - 2, 2, 2));
+    assertEquals(0, Bytes.findCommonPrefix(hello, hello, 0, 0, 0, 0));
+
+    // tests for common prefixes greater than 8 bytes in length which may use the vectorized path
+    byte[] hellohello = Bytes.toBytes("hellohello");
+    byte[] hellohellohi = Bytes.toBytes("hellohellohi");
+
+    assertEquals(10, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
+      hellohellohi.length, 0, 0));
+    assertEquals(10, Bytes.findCommonPrefix(hellohellohi, hellohello, hellohellohi.length,
+      hellohello.length, 0, 0));
+    assertEquals(10,
+      Bytes.findCommonPrefix(hellohello, hellohello, hellohello.length, hellohello.length, 0, 0));
+
+    hellohello[2] = 0;
+    assertEquals(2, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
+      hellohellohi.length, 0, 0));
   }
 }
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java
index 8f180d266c2..b451d71ed87 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtils.java
@@ -17,654 +17,12 @@
  */
 package org.apache.hadoop.hbase.util;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.HBaseCommonTestingUtility;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.nio.ByteBuff;
-import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.MiscTests;
-import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
-import org.apache.hadoop.io.WritableUtils;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-@Category({ MiscTests.class, MediumTests.class })
-@RunWith(Parameterized.class)
-public class TestByteBufferUtils {
-
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE =
-    HBaseClassTestRule.forClass(TestByteBufferUtils.class);
-
-  private static final String UNSAFE_AVAIL_NAME = "UNSAFE_AVAIL";
-  private static final String UNSAFE_UNALIGNED_NAME = "UNSAFE_UNALIGNED";
-  private byte[] array;
-
-  @AfterClass
-  public static void afterClass() throws Exception {
-    detectAvailabilityOfUnsafe();
-  }
-
-  @Parameterized.Parameters
-  public static Collection<Object[]> parameters() {
-    return HBaseCommonTestingUtility.BOOLEAN_PARAMETERIZED;
-  }
-
-  private static void setUnsafe(String fieldName, boolean value) throws Exception {
-    Field field = ByteBufferUtils.class.getDeclaredField(fieldName);
-    field.setAccessible(true);
-    Field modifiersField = ReflectionUtils.getModifiersField();
-    modifiersField.setAccessible(true);
-    int oldModifiers = field.getModifiers();
-    modifiersField.setInt(field, oldModifiers & ~Modifier.FINAL);
-    try {
-      field.set(null, value);
-    } finally {
-      modifiersField.setInt(field, oldModifiers);
-    }
-  }
-
-  static void disableUnsafe() throws Exception {
-    if (ByteBufferUtils.UNSAFE_AVAIL) {
-      setUnsafe(UNSAFE_AVAIL_NAME, false);
-    }
-    if (ByteBufferUtils.UNSAFE_UNALIGNED) {
-      setUnsafe(UNSAFE_UNALIGNED_NAME, false);
-    }
-    assertFalse(ByteBufferUtils.UNSAFE_AVAIL);
-    assertFalse(ByteBufferUtils.UNSAFE_UNALIGNED);
-  }
-
-  static void detectAvailabilityOfUnsafe() throws Exception {
-    if (ByteBufferUtils.UNSAFE_AVAIL != HBasePlatformDependent.isUnsafeAvailable()) {
-      setUnsafe(UNSAFE_AVAIL_NAME, HBasePlatformDependent.isUnsafeAvailable());
-    }
-    if (ByteBufferUtils.UNSAFE_UNALIGNED != HBasePlatformDependent.unaligned()) {
-      setUnsafe(UNSAFE_UNALIGNED_NAME, HBasePlatformDependent.unaligned());
-    }
-    assertEquals(ByteBufferUtils.UNSAFE_AVAIL, HBasePlatformDependent.isUnsafeAvailable());
-    assertEquals(ByteBufferUtils.UNSAFE_UNALIGNED, HBasePlatformDependent.unaligned());
-  }
-
-  public TestByteBufferUtils(boolean useUnsafeIfPossible) throws Exception {
-    if (useUnsafeIfPossible) {
-      detectAvailabilityOfUnsafe();
-    } else {
-      disableUnsafe();
-    }
-  }
-
-  /**
-   * Create an array with sample data.
-   */
-  @Before
-  public void setUp() {
-    array = new byte[8];
-    for (int i = 0; i < array.length; ++i) {
-      array[i] = (byte) ('a' + i);
-    }
-  }
-
-  private static final int MAX_VLONG_LENGTH = 9;
-  private static final Collection<Long> testNumbers;
-
-  private static void addNumber(Set<Long> a, long l) {
-    if (l != Long.MIN_VALUE) {
-      a.add(l - 1);
-    }
-    a.add(l);
-    if (l != Long.MAX_VALUE) {
-      a.add(l + 1);
-    }
-    for (long divisor = 3; divisor <= 10; ++divisor) {
-      for (long delta = -1; delta <= 1; ++delta) {
-        a.add(l / divisor + delta);
-      }
-    }
-  }
-
-  static {
-    SortedSet<Long> a = new TreeSet<>();
-    for (int i = 0; i <= 63; ++i) {
-      long v = -1L << i;
-      assertTrue(v < 0);
-      addNumber(a, v);
-      v = (1L << i) - 1;
-      assertTrue(v >= 0);
-      addNumber(a, v);
-    }
-
-    testNumbers = Collections.unmodifiableSet(a);
-    System.err.println("Testing variable-length long serialization using: " + testNumbers
-      + " (count: " + testNumbers.size() + ")");
-    assertEquals(1753, testNumbers.size());
-    assertEquals(Long.MIN_VALUE, a.first().longValue());
-    assertEquals(Long.MAX_VALUE, a.last().longValue());
-  }
-
-  @Test
-  public void testReadWriteVLong() {
-    for (long l : testNumbers) {
-      ByteBuffer b = ByteBuffer.allocate(MAX_VLONG_LENGTH);
-      ByteBufferUtils.writeVLong(b, l);
-      b.flip();
-      assertEquals(l, ByteBufferUtils.readVLong(b));
-      b.flip();
-      assertEquals(l, ByteBufferUtils.readVLong(ByteBuff.wrap(b)));
-    }
-  }
-
-  @Test
-  public void testReadWriteConsecutiveVLong() {
-    for (long l : testNumbers) {
-      ByteBuffer b = ByteBuffer.allocate(2 * MAX_VLONG_LENGTH);
-      ByteBufferUtils.writeVLong(b, l);
-      ByteBufferUtils.writeVLong(b, l - 4);
-      b.flip();
-      assertEquals(l, ByteBufferUtils.readVLong(b));
-      assertEquals(l - 4, ByteBufferUtils.readVLong(b));
-      b.flip();
-      assertEquals(l, ByteBufferUtils.readVLong(ByteBuff.wrap(b)));
-      assertEquals(l - 4, ByteBufferUtils.readVLong(ByteBuff.wrap(b)));
-    }
-  }
-
-  @Test
-  public void testConsistencyWithHadoopVLong() throws IOException {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    DataOutputStream dos = new DataOutputStream(baos);
-    for (long l : testNumbers) {
-      baos.reset();
-      ByteBuffer b = ByteBuffer.allocate(MAX_VLONG_LENGTH);
-      ByteBufferUtils.writeVLong(b, l);
-      String bufStr = Bytes.toStringBinary(b.array(), b.arrayOffset(), b.position());
-      WritableUtils.writeVLong(dos, l);
-      String baosStr = Bytes.toStringBinary(baos.toByteArray());
-      assertEquals(baosStr, bufStr);
-    }
-  }
-
-  /**
-   * Test copying to stream from buffer.
-   */
-  @Test
-  public void testMoveBufferToStream() throws IOException {
-    final int arrayOffset = 7;
-    final int initialPosition = 10;
-    final int endPadding = 5;
-    byte[] arrayWrapper = new byte[arrayOffset + initialPosition + array.length + endPadding];
-    System.arraycopy(array, 0, arrayWrapper, arrayOffset + initialPosition, array.length);
-    ByteBuffer buffer =
-      ByteBuffer.wrap(arrayWrapper, arrayOffset, initialPosition + array.length).slice();
-    assertEquals(initialPosition + array.length, buffer.limit());
-    assertEquals(0, buffer.position());
-    buffer.position(initialPosition);
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    ByteBufferUtils.moveBufferToStream(bos, buffer, array.length);
-    assertArrayEquals(array, bos.toByteArray());
-    assertEquals(initialPosition + array.length, buffer.position());
-  }
-
-  /**
-   * Test copying to stream from buffer with offset.
-   * @throws IOException On test failure.
-   */
-  @Test
-  public void testCopyToStreamWithOffset() throws IOException {
-    ByteBuffer buffer = ByteBuffer.wrap(array);
-
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-
-    ByteBufferUtils.copyBufferToStream(bos, buffer, array.length / 2, array.length / 2);
-
-    byte[] returnedArray = bos.toByteArray();
-    for (int i = 0; i < array.length / 2; ++i) {
-      int pos = array.length / 2 + i;
-      assertEquals(returnedArray[i], array[pos]);
-    }
-  }
-
-  /**
-   * Test copying data from stream.
-   * @throws IOException On test failure.
-   */
-  @Test
-  public void testCopyFromStream() throws IOException {
-    ByteBuffer buffer = ByteBuffer.allocate(array.length);
-    ByteArrayInputStream bis = new ByteArrayInputStream(array);
-    DataInputStream dis = new DataInputStream(bis);
-
-    ByteBufferUtils.copyFromStreamToBuffer(buffer, dis, array.length / 2);
-    ByteBufferUtils.copyFromStreamToBuffer(buffer, dis, array.length - array.length / 2);
-    for (int i = 0; i < array.length; ++i) {
-      assertEquals(array[i], buffer.get(i));
-    }
-  }
-
-  /**
-   * Test copying from buffer.
-   */
-  @Test
-  public void testCopyFromBuffer() {
-    ByteBuffer srcBuffer = ByteBuffer.allocate(array.length);
-    ByteBuffer dstBuffer = ByteBuffer.allocate(array.length);
-    srcBuffer.put(array);
-
-    ByteBufferUtils.copyFromBufferToBuffer(srcBuffer, dstBuffer, array.length / 2,
-      array.length / 4);
-    for (int i = 0; i < array.length / 4; ++i) {
-      assertEquals(srcBuffer.get(i + array.length / 2), dstBuffer.get(i));
-    }
-  }
-
-  /**
-   * Test 7-bit encoding of integers.
-   * @throws IOException On test failure.
-   */
-  @Test
-  public void testCompressedInt() throws IOException {
-    testCompressedInt(0);
-    testCompressedInt(Integer.MAX_VALUE);
-    testCompressedInt(Integer.MIN_VALUE);
-
-    for (int i = 0; i < 3; i++) {
-      testCompressedInt((128 << i) - 1);
-    }
-
-    for (int i = 0; i < 3; i++) {
-      testCompressedInt((128 << i));
-    }
-  }
-
-  /**
-   * Test how much bytes we need to store integer.
-   */
-  @Test
-  public void testIntFitsIn() {
-    assertEquals(1, ByteBufferUtils.intFitsIn(0));
-    assertEquals(1, ByteBufferUtils.intFitsIn(1));
-    assertEquals(2, ByteBufferUtils.intFitsIn(1 << 8));
-    assertEquals(3, ByteBufferUtils.intFitsIn(1 << 16));
-    assertEquals(4, ByteBufferUtils.intFitsIn(-1));
-    assertEquals(4, ByteBufferUtils.intFitsIn(Integer.MAX_VALUE));
-    assertEquals(4, ByteBufferUtils.intFitsIn(Integer.MIN_VALUE));
-  }
-
-  /**
-   * Test how much bytes we need to store long.
-   */
-  @Test
-  public void testLongFitsIn() {
-    assertEquals(1, ByteBufferUtils.longFitsIn(0));
-    assertEquals(1, ByteBufferUtils.longFitsIn(1));
-    assertEquals(3, ByteBufferUtils.longFitsIn(1L << 16));
-    assertEquals(5, ByteBufferUtils.longFitsIn(1L << 32));
-    assertEquals(8, ByteBufferUtils.longFitsIn(-1));
-    assertEquals(8, ByteBufferUtils.longFitsIn(Long.MIN_VALUE));
-    assertEquals(8, ByteBufferUtils.longFitsIn(Long.MAX_VALUE));
-  }
-
-  /**
-   * Test if we are comparing equal bytes.
-   */
-  @Test
-  public void testArePartEqual() {
-    byte[] array = new byte[] { 1, 2, 3, 4, 5, 1, 2, 3, 4 };
-    ByteBuffer buffer = ByteBuffer.wrap(array);
-    assertTrue(ByteBufferUtils.arePartsEqual(buffer, 0, 4, 5, 4));
-    assertTrue(ByteBufferUtils.arePartsEqual(buffer, 1, 2, 6, 2));
-    assertFalse(ByteBufferUtils.arePartsEqual(buffer, 1, 2, 6, 3));
-    assertFalse(ByteBufferUtils.arePartsEqual(buffer, 1, 3, 6, 2));
-    assertFalse(ByteBufferUtils.arePartsEqual(buffer, 0, 3, 6, 3));
-  }
-
-  /**
-   * Test serializing int to bytes
-   */
-  @Test
-  public void testPutInt() {
-    testPutInt(0);
-    testPutInt(Integer.MAX_VALUE);
-
-    for (int i = 0; i < 3; i++) {
-      testPutInt((128 << i) - 1);
-    }
-
-    for (int i = 0; i < 3; i++) {
-      testPutInt((128 << i));
-    }
-  }
-
-  // Utility methods invoked from test methods
-
-  private void testCompressedInt(int value) throws IOException {
-    ByteArrayOutputStream bos = new ByteArrayOutputStream();
-    ByteBufferUtils.putCompressedInt(bos, value);
-    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
-    int parsedValue = ByteBufferUtils.readCompressedInt(bis);
-    assertEquals(value, parsedValue);
-  }
-
-  private void testPutInt(int value) {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    try {
-      ByteBufferUtils.putInt(baos, value);
-    } catch (IOException e) {
-      throw new RuntimeException("Bug in putIn()", e);
-    }
-
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    DataInputStream dis = new DataInputStream(bais);
-    try {
-      assertEquals(dis.readInt(), value);
-    } catch (IOException e) {
-      throw new RuntimeException("Bug in test!", e);
-    }
-  }
-
-  @Test
-  public void testToBytes() {
-    ByteBuffer buffer = ByteBuffer.allocate(5);
-    buffer.put(new byte[] { 0, 1, 2, 3, 4 });
-    assertEquals(5, buffer.position());
-    assertEquals(5, buffer.limit());
-    byte[] copy = ByteBufferUtils.toBytes(buffer, 2);
-    assertArrayEquals(new byte[] { 2, 3, 4 }, copy);
-    assertEquals(5, buffer.position());
-    assertEquals(5, buffer.limit());
-  }
-
-  @Test
-  public void testToPrimitiveTypes() {
-    ByteBuffer buffer = ByteBuffer.allocate(15);
-    long l = 988L;
-    int i = 135;
-    short s = 7;
-    buffer.putLong(l);
-    buffer.putShort(s);
-    buffer.putInt(i);
-    assertEquals(l, ByteBufferUtils.toLong(buffer, 0));
-    assertEquals(s, ByteBufferUtils.toShort(buffer, 8));
-    assertEquals(i, ByteBufferUtils.toInt(buffer, 10));
-  }
-
-  @Test
-  public void testCopyFromArrayToBuffer() {
-    byte[] b = new byte[15];
-    b[0] = -1;
-    long l = 988L;
-    int i = 135;
-    short s = 7;
-    Bytes.putLong(b, 1, l);
-    Bytes.putShort(b, 9, s);
-    Bytes.putInt(b, 11, i);
-    ByteBuffer buffer = ByteBuffer.allocate(14);
-    ByteBufferUtils.copyFromArrayToBuffer(buffer, b, 1, 14);
-    buffer.rewind();
-    assertEquals(l, buffer.getLong());
-    assertEquals(s, buffer.getShort());
-    assertEquals(i, buffer.getInt());
-  }
-
-  private void testCopyFromSrcToDestWithThreads(Object input, Object output, List<Integer> lengthes,
-    List<Integer> offsets) throws InterruptedException {
-    assertTrue((input instanceof ByteBuffer) || (input instanceof byte[]));
-    assertTrue((output instanceof ByteBuffer) || (output instanceof byte[]));
-    assertEquals(lengthes.size(), offsets.size());
-
-    final int threads = lengthes.size();
-    CountDownLatch latch = new CountDownLatch(1);
-    List<Runnable> exes = new ArrayList<>(threads);
-    int oldInputPos = (input instanceof ByteBuffer) ? ((ByteBuffer) input).position() : 0;
-    int oldOutputPos = (output instanceof ByteBuffer) ? ((ByteBuffer) output).position() : 0;
-    for (int i = 0; i != threads; ++i) {
-      int offset = offsets.get(i);
-      int length = lengthes.get(i);
-      exes.add(() -> {
-        try {
-          latch.await();
-          if (input instanceof ByteBuffer && output instanceof byte[]) {
-            ByteBufferUtils.copyFromBufferToArray((byte[]) output, (ByteBuffer) input, offset,
-              offset, length);
-          }
-          if (input instanceof byte[] && output instanceof ByteBuffer) {
-            ByteBufferUtils.copyFromArrayToBuffer((ByteBuffer) output, offset, (byte[]) input,
-              offset, length);
-          }
-          if (input instanceof ByteBuffer && output instanceof ByteBuffer) {
-            ByteBufferUtils.copyFromBufferToBuffer((ByteBuffer) input, (ByteBuffer) output, offset,
-              offset, length);
-          }
-        } catch (InterruptedException ex) {
-          throw new RuntimeException(ex);
-        }
-      });
-    }
-    ExecutorService service = Executors.newFixedThreadPool(threads);
-    exes.forEach(service::execute);
-    latch.countDown();
-    service.shutdown();
-    assertTrue(service.awaitTermination(5, TimeUnit.SECONDS));
-    if (input instanceof ByteBuffer) {
-      assertEquals(oldInputPos, ((ByteBuffer) input).position());
-    }
-    if (output instanceof ByteBuffer) {
-      assertEquals(oldOutputPos, ((ByteBuffer) output).position());
-    }
-    String inputString = (input instanceof ByteBuffer)
-      ? Bytes.toString(Bytes.toBytes((ByteBuffer) input))
-      : Bytes.toString((byte[]) input);
-    String outputString = (output instanceof ByteBuffer)
-      ? Bytes.toString(Bytes.toBytes((ByteBuffer) output))
-      : Bytes.toString((byte[]) output);
-    assertEquals(inputString, outputString);
-  }
-
-  @Test
-  public void testCopyFromSrcToDestWithThreads() throws InterruptedException {
-    List<byte[]> words =
-      Arrays.asList(Bytes.toBytes("with"), Bytes.toBytes("great"), Bytes.toBytes("power"),
-        Bytes.toBytes("comes"), Bytes.toBytes("great"), Bytes.toBytes("responsibility"));
-    List<Integer> lengthes = words.stream().map(v -> v.length).collect(Collectors.toList());
-    List<Integer> offsets = new ArrayList<>(words.size());
-    for (int i = 0; i != words.size(); ++i) {
-      offsets.add(words.subList(0, i).stream().mapToInt(v -> v.length).sum());
-    }
-
-    int totalSize = words.stream().mapToInt(v -> v.length).sum();
-    byte[] fullContent = new byte[totalSize];
-    int offset = 0;
-    for (byte[] w : words) {
-      offset = Bytes.putBytes(fullContent, offset, w, 0, w.length);
-    }
-
-    // test copyFromBufferToArray
-    for (ByteBuffer input : Arrays.asList(ByteBuffer.allocateDirect(totalSize),
-      ByteBuffer.allocate(totalSize))) {
-      words.forEach(input::put);
-      byte[] output = new byte[totalSize];
-      testCopyFromSrcToDestWithThreads(input, output, lengthes, offsets);
-    }
-
-    // test copyFromArrayToBuffer
-    for (ByteBuffer output : Arrays.asList(ByteBuffer.allocateDirect(totalSize),
-      ByteBuffer.allocate(totalSize))) {
-      byte[] input = fullContent;
-      testCopyFromSrcToDestWithThreads(input, output, lengthes, offsets);
-    }
-
-    // test copyFromBufferToBuffer
-    for (ByteBuffer input : Arrays.asList(ByteBuffer.allocateDirect(totalSize),
-      ByteBuffer.allocate(totalSize))) {
-      words.forEach(input::put);
-      for (ByteBuffer output : Arrays.asList(ByteBuffer.allocateDirect(totalSize),
-        ByteBuffer.allocate(totalSize))) {
-        testCopyFromSrcToDestWithThreads(input, output, lengthes, offsets);
-      }
-    }
-  }
-
-  @Test
-  public void testCopyFromBufferToArray() {
-    ByteBuffer buffer = ByteBuffer.allocate(15);
-    buffer.put((byte) -1);
-    long l = 988L;
-    int i = 135;
-    short s = 7;
-    buffer.putShort(s);
-    buffer.putInt(i);
-    buffer.putLong(l);
-    byte[] b = new byte[15];
-    ByteBufferUtils.copyFromBufferToArray(b, buffer, 1, 1, 14);
-    assertEquals(s, Bytes.toShort(b, 1));
-    assertEquals(i, Bytes.toInt(b, 3));
-    assertEquals(l, Bytes.toLong(b, 7));
-  }
-
-  @Test
-  public void testRelativeCopyFromBuffertoBuffer() {
-    ByteBuffer bb1 = ByteBuffer.allocate(135);
-    ByteBuffer bb2 = ByteBuffer.allocate(135);
-    fillBB(bb1, (byte) 5);
-    ByteBufferUtils.copyFromBufferToBuffer(bb1, bb2);
-    assertTrue(bb1.position() == bb2.position());
-    assertTrue(bb1.limit() == bb2.limit());
-    bb1 = ByteBuffer.allocateDirect(135);
-    bb2 = ByteBuffer.allocateDirect(135);
-    fillBB(bb1, (byte) 5);
-    ByteBufferUtils.copyFromBufferToBuffer(bb1, bb2);
-    assertTrue(bb1.position() == bb2.position());
-    assertTrue(bb1.limit() == bb2.limit());
-  }
-
-  @Test
-  public void testCompareTo() {
-    ByteBuffer bb1 = ByteBuffer.allocate(135);
-    ByteBuffer bb2 = ByteBuffer.allocate(135);
-    byte[] b = new byte[71];
-    fillBB(bb1, (byte) 5);
-    fillBB(bb2, (byte) 5);
-    fillArray(b, (byte) 5);
-    assertEquals(0, ByteBufferUtils.compareTo(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()));
-    assertTrue(ByteBufferUtils.compareTo(bb1, 0, bb1.remaining(), b, 0, b.length) > 0);
-    bb2.put(134, (byte) 6);
-    assertTrue(ByteBufferUtils.compareTo(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()) < 0);
-    bb2.put(6, (byte) 4);
-    assertTrue(ByteBufferUtils.compareTo(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()) > 0);
-    // Assert reverse comparing BB and bytearray works.
-    ByteBuffer bb3 = ByteBuffer.allocate(135);
-    fillBB(bb3, (byte) 0);
-    byte[] b3 = new byte[135];
-    fillArray(b3, (byte) 1);
-    int result = ByteBufferUtils.compareTo(b3, 0, b3.length, bb3, 0, bb3.remaining());
-    assertTrue(result > 0);
-    result = ByteBufferUtils.compareTo(bb3, 0, bb3.remaining(), b3, 0, b3.length);
-    assertTrue(result < 0);
-    byte[] b4 = Bytes.toBytes("123");
-    ByteBuffer bb4 = ByteBuffer.allocate(10 + b4.length);
-    for (int i = 10; i < bb4.capacity(); ++i) {
-      bb4.put(i, b4[i - 10]);
-    }
-    result = ByteBufferUtils.compareTo(b4, 0, b4.length, bb4, 10, b4.length);
-    assertEquals(0, result);
-  }
-
-  @Test
-  public void testEquals() {
-    byte[] a = Bytes.toBytes("http://A");
-    ByteBuffer bb = ByteBuffer.wrap(a);
-
-    assertTrue(ByteBufferUtils.equals(HConstants.EMPTY_BYTE_BUFFER, 0, 0,
-      HConstants.EMPTY_BYTE_BUFFER, 0, 0));
-
-    assertFalse(ByteBufferUtils.equals(HConstants.EMPTY_BYTE_BUFFER, 0, 0, bb, 0, a.length));
-
-    assertFalse(ByteBufferUtils.equals(bb, 0, 0, HConstants.EMPTY_BYTE_BUFFER, 0, a.length));
-
-    assertTrue(ByteBufferUtils.equals(bb, 0, a.length, bb, 0, a.length));
-
-    assertTrue(ByteBufferUtils.equals(HConstants.EMPTY_BYTE_BUFFER, 0, 0,
-      HConstants.EMPTY_BYTE_ARRAY, 0, 0));
-
-    assertFalse(ByteBufferUtils.equals(HConstants.EMPTY_BYTE_BUFFER, 0, 0, a, 0, a.length));
-
-    assertFalse(ByteBufferUtils.equals(bb, 0, a.length, HConstants.EMPTY_BYTE_ARRAY, 0, 0));
-
-    assertTrue(ByteBufferUtils.equals(bb, 0, a.length, a, 0, a.length));
-  }
-
-  @Test
-  public void testFindCommonPrefix() {
-    ByteBuffer bb1 = ByteBuffer.allocate(135);
-    ByteBuffer bb2 = ByteBuffer.allocate(135);
-    ByteBuffer bb3 = ByteBuffer.allocateDirect(135);
-    byte[] b = new byte[71];
-
-    fillBB(bb1, (byte) 5);
-    fillBB(bb2, (byte) 5);
-    fillBB(bb3, (byte) 5);
-    fillArray(b, (byte) 5);
-
-    assertEquals(135,
-      ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()));
-    assertEquals(71, ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), b, 0, b.length));
-    assertEquals(135,
-      ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), bb3, 0, bb3.remaining()));
-    assertEquals(71, ByteBufferUtils.findCommonPrefix(bb3, 0, bb3.remaining(), b, 0, b.length));
-
-    b[13] = 9;
-    assertEquals(13, ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), b, 0, b.length));
-
-    bb2.put(134, (byte) 6);
-    assertEquals(134,
-      ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()));
-
-    bb2.put(6, (byte) 4);
-    assertEquals(6,
-      ByteBufferUtils.findCommonPrefix(bb1, 0, bb1.remaining(), bb2, 0, bb2.remaining()));
-  }
-
-  private static void fillBB(ByteBuffer bb, byte b) {
-    for (int i = bb.position(); i < bb.limit(); i++) {
-      bb.put(i, b);
-    }
-  }
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.jupiter.api.Tag;
 
-  private static void fillArray(byte[] bb, byte b) {
-    for (int i = 0; i < bb.length; i++) {
-      bb[i] = b;
-    }
-  }
+@Tag(MiscTests.TAG)
+@Tag(SmallTests.TAG)
+public class TestByteBufferUtils extends ByteBufferUtilsTestBase {
 
 }
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtilsWoUnsafe.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtilsWoUnsafe.java
new file mode 100644
index 00000000000..c02db2142c1
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestByteBufferUtilsWoUnsafe.java
@@ -0,0 +1,43 @@
+/*
+ * 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.hbase.util;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.mockito.Mockito.mockStatic;
+
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.mockito.MockedStatic;
+
+@Tag(MiscTests.TAG)
+@Tag(SmallTests.TAG)
+public class TestByteBufferUtilsWoUnsafe extends ByteBufferUtilsTestBase {
+
+  @BeforeAll
+  public static void disableUnsafe() {
+    try (MockedStatic<HBasePlatformDependent> mocked = mockStatic(HBasePlatformDependent.class)) {
+      mocked.when(HBasePlatformDependent::isUnsafeAvailable).thenReturn(false);
+      mocked.when(HBasePlatformDependent::unaligned).thenReturn(false);
+      assertFalse(ByteBufferUtils.UNSAFE_AVAIL);
+      assertFalse(ByteBufferUtils.UNSAFE_UNALIGNED);
+    }
+  }
+}
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java
index b7434895998..0122e91d7ea 100644
--- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java
@@ -17,615 +17,12 @@
  */
 package org.apache.hadoop.hbase.util;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.math.BigDecimal;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.ThreadLocalRandom;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.MiscTests;
-import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
-import org.apache.hadoop.io.WritableUtils;
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category({ MiscTests.class, MediumTests.class })
-public class TestBytes {
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE = HBaseClassTestRule.forClass(TestBytes.class);
-
-  private static void setUnsafe(boolean value) throws Exception {
-    Field field = Bytes.class.getDeclaredField("UNSAFE_UNALIGNED");
-    field.setAccessible(true);
-
-    Field modifiersField = ReflectionUtils.getModifiersField();
-    modifiersField.setAccessible(true);
-    int oldModifiers = field.getModifiers();
-    modifiersField.setInt(field, oldModifiers & ~Modifier.FINAL);
-    try {
-      field.set(null, value);
-    } finally {
-      modifiersField.setInt(field, oldModifiers);
-    }
-    assertEquals(Bytes.UNSAFE_UNALIGNED, value);
-  }
-
-  @Test
-  public void testShort() throws Exception {
-    testShort(false);
-  }
-
-  @Test
-  public void testShortUnsafe() throws Exception {
-    testShort(true);
-  }
-
-  private static void testShort(boolean unsafe) throws Exception {
-    setUnsafe(unsafe);
-    try {
-      for (short n : Arrays.asList(Short.MIN_VALUE, (short) -100, (short) -1, (short) 0, (short) 1,
-        (short) 300, Short.MAX_VALUE)) {
-        byte[] bytes = Bytes.toBytes(n);
-        assertEquals(Bytes.toShort(bytes, 0, bytes.length), n);
-      }
-    } finally {
-      setUnsafe(HBasePlatformDependent.unaligned());
-    }
-  }
-
-  @Test
-  public void testNullHashCode() {
-    byte[] b = null;
-    Exception ee = null;
-    try {
-      Bytes.hashCode(b);
-    } catch (Exception e) {
-      ee = e;
-    }
-    assertNotNull(ee);
-  }
-
-  @Test
-  public void testAdd() {
-    byte[] a = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-    byte[] b = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
-    byte[] c = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
-    byte[] result1 = Bytes.add(a, b, c);
-    byte[] result2 = Bytes.add(new byte[][] { a, b, c });
-    assertEquals(0, Bytes.compareTo(result1, result2));
-  }
-
-  @Test
-  public void testSplit() {
-    byte[] lowest = Bytes.toBytes("AAA");
-    byte[] middle = Bytes.toBytes("CCC");
-    byte[] highest = Bytes.toBytes("EEE");
-    byte[][] parts = Bytes.split(lowest, highest, 1);
-    for (byte[] bytes : parts) {
-      System.out.println(Bytes.toString(bytes));
-    }
-    assertEquals(3, parts.length);
-    assertTrue(Bytes.equals(parts[1], middle));
-    // Now divide into three parts. Change highest so split is even.
-    highest = Bytes.toBytes("DDD");
-    parts = Bytes.split(lowest, highest, 2);
-    for (byte[] part : parts) {
-      System.out.println(Bytes.toString(part));
-    }
-    assertEquals(4, parts.length);
-    // Assert that 3rd part is 'CCC'.
-    assertTrue(Bytes.equals(parts[2], middle));
-  }
-
-  @Test
-  public void testSplit2() {
-    // More split tests.
-    byte[] lowest = Bytes.toBytes("http://A");
-    byte[] highest = Bytes.toBytes("http://z");
-    byte[] middle = Bytes.toBytes("http://]");
-    byte[][] parts = Bytes.split(lowest, highest, 1);
-    for (byte[] part : parts) {
-      System.out.println(Bytes.toString(part));
-    }
-    assertEquals(3, parts.length);
-    assertTrue(Bytes.equals(parts[1], middle));
-  }
-
-  @Test
-  public void testSplit3() {
-    // Test invalid split cases
-    byte[] low = { 1, 1, 1 };
-    byte[] high = { 1, 1, 3 };
-
-    // If swapped, should throw IAE
-    try {
-      Bytes.split(high, low, 1);
-      fail("Should not be able to split if low > high");
-    } catch (IllegalArgumentException iae) {
-      // Correct
-    }
-
-    // Single split should work
-    byte[][] parts = Bytes.split(low, high, 1);
-    for (int i = 0; i < parts.length; i++) {
-      System.out.println("" + i + " -> " + Bytes.toStringBinary(parts[i]));
-    }
-    assertEquals("Returned split should have 3 parts but has " + parts.length, 3, parts.length);
-
-    // If split more than once, use additional byte to split
-    parts = Bytes.split(low, high, 2);
-    assertNotNull("Split with an additional byte", parts);
-    assertEquals(parts.length, low.length + 1);
-
-    // Split 0 times should throw IAE
-    try {
-      Bytes.split(low, high, 0);
-      fail("Should not be able to split 0 times");
-    } catch (IllegalArgumentException iae) {
-      // Correct
-    }
-  }
-
-  @Test
-  public void testToInt() {
-    int[] ints = { -1, 123, Integer.MIN_VALUE, Integer.MAX_VALUE };
-    for (int anInt : ints) {
-      byte[] b = Bytes.toBytes(anInt);
-      assertEquals(anInt, Bytes.toInt(b));
-      byte[] b2 = bytesWithOffset(b);
-      assertEquals(anInt, Bytes.toInt(b2, 1));
-      assertEquals(anInt, Bytes.toInt(b2, 1, Bytes.SIZEOF_INT));
-    }
-  }
-
-  @Test
-  public void testToLong() {
-    long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
-    for (long aLong : longs) {
-      byte[] b = Bytes.toBytes(aLong);
-      assertEquals(aLong, Bytes.toLong(b));
-      byte[] b2 = bytesWithOffset(b);
-      assertEquals(aLong, Bytes.toLong(b2, 1));
-      assertEquals(aLong, Bytes.toLong(b2, 1, Bytes.SIZEOF_LONG));
-    }
-  }
-
-  @Test
-  public void testToFloat() {
-    float[] floats = { -1f, 123.123f, Float.MAX_VALUE };
-    for (float aFloat : floats) {
-      byte[] b = Bytes.toBytes(aFloat);
-      assertEquals(aFloat, Bytes.toFloat(b), 0.0f);
-      byte[] b2 = bytesWithOffset(b);
-      assertEquals(aFloat, Bytes.toFloat(b2, 1), 0.0f);
-    }
-  }
-
-  @Test
-  public void testToDouble() {
-    double[] doubles = { Double.MIN_VALUE, Double.MAX_VALUE };
-    for (double aDouble : doubles) {
-      byte[] b = Bytes.toBytes(aDouble);
-      assertEquals(aDouble, Bytes.toDouble(b), 0.0);
-      byte[] b2 = bytesWithOffset(b);
-      assertEquals(aDouble, Bytes.toDouble(b2, 1), 0.0);
-    }
-  }
-
-  @Test
-  public void testToBigDecimal() {
-    BigDecimal[] decimals =
-      { new BigDecimal("-1"), new BigDecimal("123.123"), new BigDecimal("123123123123") };
-    for (BigDecimal decimal : decimals) {
-      byte[] b = Bytes.toBytes(decimal);
-      assertEquals(decimal, Bytes.toBigDecimal(b));
-      byte[] b2 = bytesWithOffset(b);
-      assertEquals(decimal, Bytes.toBigDecimal(b2, 1, b.length));
-    }
-  }
-
-  private byte[] bytesWithOffset(byte[] src) {
-    // add one byte in front to test offset
-    byte[] result = new byte[src.length + 1];
-    result[0] = (byte) 0xAA;
-    System.arraycopy(src, 0, result, 1, src.length);
-    return result;
-  }
-
-  @Test
-  public void testToBytesForByteBuffer() {
-    byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-    ByteBuffer target = ByteBuffer.wrap(array);
-    target.position(2);
-    target.limit(7);
-
-    byte[] actual = Bytes.toBytes(target);
-    byte[] expected = { 0, 1, 2, 3, 4, 5, 6 };
-    assertArrayEquals(expected, actual);
-    assertEquals(2, target.position());
-    assertEquals(7, target.limit());
-
-    ByteBuffer target2 = target.slice();
-    assertEquals(0, target2.position());
-    assertEquals(5, target2.limit());
-
-    byte[] actual2 = Bytes.toBytes(target2);
-    byte[] expected2 = { 2, 3, 4, 5, 6 };
-    assertArrayEquals(expected2, actual2);
-    assertEquals(0, target2.position());
-    assertEquals(5, target2.limit());
-  }
-
-  @Test
-  public void testGetBytesForByteBuffer() {
-    byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
-    ByteBuffer target = ByteBuffer.wrap(array);
-    target.position(2);
-    target.limit(7);
-
-    byte[] actual = Bytes.getBytes(target);
-    byte[] expected = { 2, 3, 4, 5, 6 };
-    assertArrayEquals(expected, actual);
-    assertEquals(2, target.position());
-    assertEquals(7, target.limit());
-  }
-
-  @Test
-  public void testReadAsVLong() throws Exception {
-    long[] longs = { -1L, 123L, Long.MIN_VALUE, Long.MAX_VALUE };
-    for (long aLong : longs) {
-      ByteArrayOutputStream baos = new ByteArrayOutputStream();
-      DataOutputStream output = new DataOutputStream(baos);
-      WritableUtils.writeVLong(output, aLong);
-      byte[] long_bytes_no_offset = baos.toByteArray();
-      assertEquals(aLong, Bytes.readAsVLong(long_bytes_no_offset, 0));
-      byte[] long_bytes_with_offset = bytesWithOffset(long_bytes_no_offset);
-      assertEquals(aLong, Bytes.readAsVLong(long_bytes_with_offset, 1));
-    }
-  }
-
-  @Test
-  public void testToStringBinaryForBytes() {
-    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
-    String actual = Bytes.toStringBinary(array);
-    String expected = "09azAZ@\\x01";
-    assertEquals(expected, actual);
-
-    String actual2 = Bytes.toStringBinary(array, 2, 3);
-    String expected2 = "azA";
-    assertEquals(expected2, actual2);
-  }
-
-  @Test
-  public void testToStringBinaryForArrayBasedByteBuffer() {
-    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
-    ByteBuffer target = ByteBuffer.wrap(array);
-    String actual = Bytes.toStringBinary(target);
-    String expected = "09azAZ@\\x01";
-    assertEquals(expected, actual);
-  }
-
-  @Test
-  public void testToStringBinaryForReadOnlyByteBuffer() {
-    byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 };
-    ByteBuffer target = ByteBuffer.wrap(array).asReadOnlyBuffer();
-    String actual = Bytes.toStringBinary(target);
-    String expected = "09azAZ@\\x01";
-    assertEquals(expected, actual);
-  }
-
-  @Test
-  public void testBinarySearch() {
-    byte[][] arr = { { 1 }, { 3 }, { 5 }, { 7 }, { 9 }, { 11 }, { 13 }, { 15 }, };
-    byte[] key1 = { 3, 1 };
-    byte[] key2 = { 4, 9 };
-    byte[] key2_2 = { 4 };
-    byte[] key3 = { 5, 11 };
-    byte[] key4 = { 0 };
-    byte[] key5 = { 2 };
-
-    assertEquals(1, Bytes.binarySearch(arr, key1, 0, 1));
-    assertEquals(0, Bytes.binarySearch(arr, key1, 1, 1));
-    assertEquals(-(2 + 1), Arrays.binarySearch(arr, key2_2, Bytes.BYTES_COMPARATOR));
-    assertEquals(-(2 + 1), Bytes.binarySearch(arr, key2, 0, 1));
-    assertEquals(4, Bytes.binarySearch(arr, key2, 1, 1));
-    assertEquals(2, Bytes.binarySearch(arr, key3, 0, 1));
-    assertEquals(5, Bytes.binarySearch(arr, key3, 1, 1));
-    assertEquals(-1, Bytes.binarySearch(arr, key4, 0, 1));
-    assertEquals(-2, Bytes.binarySearch(arr, key5, 0, 1));
-
-    // Search for values to the left and to the right of each item in the array.
-    for (int i = 0; i < arr.length; ++i) {
-      assertEquals(-(i + 1), Bytes.binarySearch(arr, new byte[] { (byte) (arr[i][0] - 1) }, 0, 1));
-      assertEquals(-(i + 2), Bytes.binarySearch(arr, new byte[] { (byte) (arr[i][0] + 1) }, 0, 1));
-    }
-  }
-
-  @Test
-  public void testToStringBytesBinaryReversible() {
-    byte[] randomBytes = new byte[1000];
-    for (int i = 0; i < 1000; i++) {
-      Bytes.random(randomBytes);
-      verifyReversibleForBytes(randomBytes);
-    }
-    // some specific cases
-    verifyReversibleForBytes(new byte[] {});
-    verifyReversibleForBytes(new byte[] { '\\', 'x', 'A', 'D' });
-    verifyReversibleForBytes(new byte[] { '\\', 'x', 'A', 'D', '\\' });
-  }
-
-  private void verifyReversibleForBytes(byte[] originalBytes) {
-    String convertedString = Bytes.toStringBinary(originalBytes);
-    byte[] convertedBytes = Bytes.toBytesBinary(convertedString);
-    if (Bytes.compareTo(originalBytes, convertedBytes) != 0) {
-      fail("Not reversible for\nbyte[]: " + Arrays.toString(originalBytes) + ",\nStringBinary: "
-        + convertedString);
-    }
-  }
-
-  @Test
-  public void testStartsWith() {
-    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("h")));
-    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("")));
-    assertTrue(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("hello")));
-    assertFalse(Bytes.startsWith(Bytes.toBytes("hello"), Bytes.toBytes("helloworld")));
-    assertFalse(Bytes.startsWith(Bytes.toBytes(""), Bytes.toBytes("hello")));
-  }
-
-  @Test
-  public void testIncrementBytes() {
-    assertTrue(checkTestIncrementBytes(10, 1));
-    assertTrue(checkTestIncrementBytes(12, 123435445));
-    assertTrue(checkTestIncrementBytes(124634654, 1));
-    assertTrue(checkTestIncrementBytes(10005460, 5005645));
-    assertTrue(checkTestIncrementBytes(1, -1));
-    assertTrue(checkTestIncrementBytes(10, -1));
-    assertTrue(checkTestIncrementBytes(10, -5));
-    assertTrue(checkTestIncrementBytes(1005435000, -5));
-    assertTrue(checkTestIncrementBytes(10, -43657655));
-    assertTrue(checkTestIncrementBytes(-1, 1));
-    assertTrue(checkTestIncrementBytes(-26, 5034520));
-    assertTrue(checkTestIncrementBytes(-10657200, 5));
-    assertTrue(checkTestIncrementBytes(-12343250, 45376475));
-    assertTrue(checkTestIncrementBytes(-10, -5));
-    assertTrue(checkTestIncrementBytes(-12343250, -5));
-    assertTrue(checkTestIncrementBytes(-12, -34565445));
-    assertTrue(checkTestIncrementBytes(-1546543452, -34565445));
-  }
-
-  private static boolean checkTestIncrementBytes(long val, long amount) {
-    byte[] value = Bytes.toBytes(val);
-    byte[] testValue = { -1, -1, -1, -1, -1, -1, -1, -1 };
-    if (value[0] > 0) {
-      testValue = new byte[Bytes.SIZEOF_LONG];
-    }
-    System.arraycopy(value, 0, testValue, testValue.length - value.length, value.length);
-
-    long incrementResult = Bytes.toLong(Bytes.incrementBytes(value, amount));
-
-    return (Bytes.toLong(testValue) + amount) == incrementResult;
-  }
-
-  @Test
-  public void testFixedSizeString() throws IOException {
-    ByteArrayOutputStream baos = new ByteArrayOutputStream();
-    DataOutputStream dos = new DataOutputStream(baos);
-    Bytes.writeStringFixedSize(dos, "Hello", 5);
-    Bytes.writeStringFixedSize(dos, "World", 18);
-    Bytes.writeStringFixedSize(dos, "", 9);
-
-    try {
-      // Use a long dash which is three bytes in UTF-8. If encoding happens
-      // using ISO-8859-1, this will fail.
-      Bytes.writeStringFixedSize(dos, "Too\u2013Long", 9);
-      fail("Exception expected");
-    } catch (IOException ex) {
-      assertEquals(
-        "Trying to write 10 bytes (Too\\xE2\\x80\\x93Long) into a field of " + "length 9",
-        ex.getMessage());
-    }
-
-    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
-    DataInputStream dis = new DataInputStream(bais);
-    assertEquals("Hello", Bytes.readStringFixedSize(dis, 5));
-    assertEquals("World", Bytes.readStringFixedSize(dis, 18));
-    assertEquals("", Bytes.readStringFixedSize(dis, 9));
-  }
-
-  @Test
-  public void testCopy() {
-    byte[] bytes = Bytes.toBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-    byte[] copy = Bytes.copy(bytes);
-    assertNotSame(bytes, copy);
-    assertTrue(Bytes.equals(bytes, copy));
-  }
-
-  @Test
-  public void testToBytesBinaryTrailingBackslashes() {
-    try {
-      Bytes.toBytesBinary("abc\\x00\\x01\\");
-    } catch (StringIndexOutOfBoundsException ex) {
-      fail("Illegal string access: " + ex.getMessage());
-    }
-  }
-
-  @Test
-  public void testToStringBinary_toBytesBinary_Reversable() {
-    String bytes = Bytes.toStringBinary(Bytes.toBytes(2.17));
-    assertEquals(2.17, Bytes.toDouble(Bytes.toBytesBinary(bytes)), 0);
-  }
-
-  @Test
-  public void testUnsignedBinarySearch() {
-    byte[] bytes = new byte[] { 0, 5, 123, 127, -128, -100, -1 };
-    Assert.assertEquals(1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 5));
-    Assert.assertEquals(3, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 127));
-    Assert.assertEquals(4, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -128));
-    Assert.assertEquals(5, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -100));
-    Assert.assertEquals(6, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -1));
-    Assert.assertEquals(-1 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) 2));
-    Assert.assertEquals(-6 - 1, Bytes.unsignedBinarySearch(bytes, 0, bytes.length, (byte) -5));
-  }
-
-  @Test
-  public void testUnsignedIncrement() {
-    byte[] a = Bytes.toBytes(0);
-    int a2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(a), 0);
-    Assert.assertEquals(1, a2);
-
-    byte[] b = Bytes.toBytes(-1);
-    byte[] actual = Bytes.unsignedCopyAndIncrement(b);
-    Assert.assertNotSame(b, actual);
-    byte[] expected = new byte[] { 1, 0, 0, 0, 0 };
-    assertArrayEquals(expected, actual);
-
-    byte[] c = Bytes.toBytes(255);// should wrap to the next significant byte
-    int c2 = Bytes.toInt(Bytes.unsignedCopyAndIncrement(c), 0);
-    Assert.assertEquals(256, c2);
-  }
-
-  @Test
-  public void testIndexOf() {
-    byte[] array = Bytes.toBytes("hello");
-    assertEquals(1, Bytes.indexOf(array, (byte) 'e'));
-    assertEquals(4, Bytes.indexOf(array, (byte) 'o'));
-    assertEquals(-1, Bytes.indexOf(array, (byte) 'a'));
-    assertEquals(0, Bytes.indexOf(array, Bytes.toBytes("hel")));
-    assertEquals(2, Bytes.indexOf(array, Bytes.toBytes("ll")));
-    assertEquals(-1, Bytes.indexOf(array, Bytes.toBytes("hll")));
-  }
-
-  @Test
-  public void testContains() {
-    byte[] array = Bytes.toBytes("hello world");
-    assertTrue(Bytes.contains(array, (byte) 'e'));
-    assertTrue(Bytes.contains(array, (byte) 'd'));
-    assertFalse(Bytes.contains(array, (byte) 'a'));
-    assertTrue(Bytes.contains(array, Bytes.toBytes("world")));
-    assertTrue(Bytes.contains(array, Bytes.toBytes("ello")));
-    assertFalse(Bytes.contains(array, Bytes.toBytes("owo")));
-  }
-
-  @Test
-  public void testZero() {
-    byte[] array = Bytes.toBytes("hello");
-    Bytes.zero(array);
-    for (byte b : array) {
-      assertEquals(0, b);
-    }
-    array = Bytes.toBytes("hello world");
-    Bytes.zero(array, 2, 7);
-    assertFalse(array[0] == 0);
-    assertFalse(array[1] == 0);
-    for (int i = 2; i < 9; i++) {
-      assertEquals(0, array[i]);
-    }
-    for (int i = 9; i < array.length; i++) {
-      assertFalse(array[i] == 0);
-    }
-  }
-
-  @Test
-  public void testPutBuffer() {
-    byte[] b = new byte[100];
-    for (byte i = 0; i < 100; i++) {
-      Bytes.putByteBuffer(b, i, ByteBuffer.wrap(new byte[] { i }));
-    }
-    for (byte i = 0; i < 100; i++) {
-      Assert.assertEquals(i, b[i]);
-    }
-  }
-
-  @Test
-  public void testToFromHex() {
-    List<String> testStrings = new ArrayList<>(8);
-    testStrings.addAll(Arrays.asList("", "00", "A0", "ff", "FFffFFFFFFFFFF", "12",
-      "0123456789abcdef", "283462839463924623984692834692346ABCDFEDDCA0"));
-    for (String testString : testStrings) {
-      byte[] byteData = Bytes.fromHex(testString);
-      Assert.assertEquals(testString.length() / 2, byteData.length);
-      String result = Bytes.toHex(byteData);
-      Assert.assertTrue(testString.equalsIgnoreCase(result));
-    }
-
-    List<byte[]> testByteData = new ArrayList<>(5);
-    testByteData.addAll(Arrays.asList(new byte[0], new byte[1], new byte[10],
-      new byte[] { 1, 2, 3, 4, 5 }, new byte[] { (byte) 0xFF }));
-    Random rand = ThreadLocalRandom.current();
-    for (int i = 0; i < 20; i++) {
-      byte[] bytes = new byte[rand.nextInt(100)];
-      Bytes.random(bytes);
-      testByteData.add(bytes);
-    }
-
-    for (byte[] testData : testByteData) {
-      String hexString = Bytes.toHex(testData);
-      Assert.assertEquals(testData.length * 2, hexString.length());
-      byte[] result = Bytes.fromHex(hexString);
-      assertArrayEquals(testData, result);
-    }
-  }
-
-  @Test
-  public void testFindCommonPrefix() throws Exception {
-    testFindCommonPrefix(false);
-  }
-
-  @Test
-  public void testFindCommonPrefixUnsafe() throws Exception {
-    testFindCommonPrefix(true);
-  }
-
-  private static void testFindCommonPrefix(boolean unsafe) throws Exception {
-    setUnsafe(unsafe);
-    try {
-      // tests for common prefixes less than 8 bytes in length (i.e. using non-vectorized path)
-      byte[] hello = Bytes.toBytes("hello");
-      byte[] helloWorld = Bytes.toBytes("helloworld");
-
-      assertEquals(5,
-        Bytes.findCommonPrefix(hello, helloWorld, hello.length, helloWorld.length, 0, 0));
-      assertEquals(5, Bytes.findCommonPrefix(hello, hello, hello.length, hello.length, 0, 0));
-      assertEquals(3,
-        Bytes.findCommonPrefix(hello, hello, hello.length - 2, hello.length - 2, 2, 2));
-      assertEquals(0, Bytes.findCommonPrefix(hello, hello, 0, 0, 0, 0));
-
-      // tests for common prefixes greater than 8 bytes in length which may use the vectorized path
-      byte[] hellohello = Bytes.toBytes("hellohello");
-      byte[] hellohellohi = Bytes.toBytes("hellohellohi");
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.jupiter.api.Tag;
 
-      assertEquals(10, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
-        hellohellohi.length, 0, 0));
-      assertEquals(10, Bytes.findCommonPrefix(hellohellohi, hellohello, hellohellohi.length,
-        hellohello.length, 0, 0));
-      assertEquals(10,
-        Bytes.findCommonPrefix(hellohello, hellohello, hellohello.length, hellohello.length, 0, 0));
+@Tag(MiscTests.TAG)
+@Tag(SmallTests.TAG)
+public class TestBytes extends BytesTestBase {
 
-      hellohello[2] = 0;
-      assertEquals(2, Bytes.findCommonPrefix(hellohello, hellohellohi, hellohello.length,
-        hellohellohi.length, 0, 0));
-    } finally {
-      setUnsafe(HBasePlatformDependent.unaligned());
-    }
-  }
 }
diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytesWoUnsafe.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytesWoUnsafe.java
new file mode 100644
index 00000000000..8aacab4b851
--- /dev/null
+++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytesWoUnsafe.java
@@ -0,0 +1,41 @@
+/*
+ * 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.hbase.util;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.mockito.Mockito.mockStatic;
+
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.mockito.MockedStatic;
+
+@Tag(MiscTests.TAG)
+@Tag(SmallTests.TAG)
+public class TestBytesWoUnsafe extends BytesTestBase {
+
+  @BeforeAll
+  public static void disableUnsafe() {
+    try (MockedStatic<HBasePlatformDependent> mocked = mockStatic(HBasePlatformDependent.class)) {
+      mocked.when(HBasePlatformDependent::unaligned).thenReturn(false);
+      assertFalse(Bytes.UNSAFE_UNALIGNED);
+    }
+  }
+}
diff --git a/hbase-server/pom.xml b/hbase-server/pom.xml
index ea332ba5d60..6585117cc5f 100644
--- a/hbase-server/pom.xml
+++ b/hbase-server/pom.xml
@@ -317,6 +317,11 @@
       <artifactId>mockito-core</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-inline</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>jcl-over-slf4j</artifactId>
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestHBaseTestingUtility.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestHBaseTestingUtility.java
index 2f0f15de670..283981caa9b 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestHBaseTestingUtility.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestHBaseTestingUtility.java
@@ -21,13 +21,9 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import java.io.File;
 import java.util.List;
-import java.util.Random;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.FileUtil;
@@ -48,9 +44,6 @@ import org.junit.Rule;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
 import org.junit.rules.TestName;
-import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -412,38 +405,8 @@ public class TestHBaseTestingUtility {
     assertTrue(hbt.cleanupTestDir());
   }
 
-  @Test
-  public void testResolvePortConflict() throws Exception {
-    // raises port conflict between 1st call and 2nd call of randomPort() by mocking Random object
-    Random random = mock(Random.class);
-    when(random.nextInt(anyInt())).thenAnswer(new Answer<Integer>() {
-      int[] numbers = { 1, 1, 2 };
-      int count = 0;
-
-      @Override
-      public Integer answer(InvocationOnMock invocation) {
-        int ret = numbers[count];
-        count++;
-        return ret;
-      }
-    });
-
-    HBaseTestingUtility.PortAllocator.AvailablePortChecker portChecker =
-      mock(HBaseTestingUtility.PortAllocator.AvailablePortChecker.class);
-    when(portChecker.available(anyInt())).thenReturn(true);
-
-    HBaseTestingUtility.PortAllocator portAllocator =
-      new HBaseTestingUtility.PortAllocator(random, portChecker);
-
-    int port1 = portAllocator.randomFreePort();
-    int port2 = portAllocator.randomFreePort();
-    assertNotEquals(port1, port2);
-    Mockito.verify(random, Mockito.times(3)).nextInt(anyInt());
-  }
-
   @Test
   public void testOverridingOfDefaultPorts() throws Exception {
-
     // confirm that default port properties being overridden to random
     Configuration defaultConfig = HBaseConfiguration.create();
     defaultConfig.setInt(HConstants.MASTER_INFO_PORT, HConstants.DEFAULT_MASTER_INFOPORT);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/TestPortAllocator.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestPortAllocator.java
new file mode 100644
index 00000000000..1fc62516844
--- /dev/null
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/TestPortAllocator.java
@@ -0,0 +1,67 @@
+/*
+ * 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.hbase;
+
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.Random;
+import org.apache.hadoop.hbase.testclassification.MiscTests;
+import org.apache.hadoop.hbase.testclassification.SmallTests;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+@Tag(MiscTests.TAG)
+@Tag(SmallTests.TAG)
+public class TestPortAllocator {
+
+  @Test
+  public void testResolvePortConflict() throws Exception {
+    // raises port conflict between 1st call and 2nd call of randomPort() by mocking Random object
+    Random random = mock(Random.class);
+    when(random.nextInt(anyInt())).thenAnswer(new Answer<Integer>() {
+      int[] numbers = { 1, 1, 2 };
+      int count = 0;
+
+      @Override
+      public Integer answer(InvocationOnMock invocation) {
+        int ret = numbers[count];
+        count++;
+        return ret;
+      }
+    });
+
+    HBaseTestingUtility.PortAllocator.AvailablePortChecker portChecker =
+      mock(HBaseTestingUtility.PortAllocator.AvailablePortChecker.class);
+    when(portChecker.available(anyInt())).thenReturn(true);
+
+    HBaseTestingUtility.PortAllocator portAllocator =
+      new HBaseTestingUtility.PortAllocator(random, portChecker);
+
+    int port1 = portAllocator.randomFreePort();
+    int port2 = portAllocator.randomFreePort();
+    assertNotEquals(port1, port2);
+    verify(random, Mockito.times(3)).nextInt(anyInt());
+  }
+}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/FromClientSide3TestBase.java
similarity index 93%
copy from hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
copy to hbase-server/src/test/java/org/apache/hadoop/hbase/client/FromClientSide3TestBase.java
index aed5ba707c0..cfaed98d6ba 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/FromClientSide3TestBase.java
@@ -17,11 +17,11 @@
  */
 package org.apache.hadoop.hbase.client;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -40,7 +40,6 @@ import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.Coprocessor;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtility;
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
@@ -59,81 +58,65 @@ import org.apache.hadoop.hbase.regionserver.HRegion;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
 import org.apache.hadoop.hbase.regionserver.RegionScanner;
-import org.apache.hadoop.hbase.testclassification.ClientTests;
-import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.util.Pair;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
 
-@Category({ LargeTests.class, ClientTests.class })
-public class TestFromClientSide3 {
-
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE =
-    HBaseClassTestRule.forClass(TestFromClientSide3.class);
-
-  private static final Logger LOG = LoggerFactory.getLogger(TestFromClientSide3.class);
-  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
-  private static final int WAITTABLE_MILLIS = 10000;
-  private static byte[] FAMILY = Bytes.toBytes("testFamily");
-  private static int SLAVES = 3;
-  private static final byte[] ROW = Bytes.toBytes("testRow");
-  private static final byte[] ANOTHERROW = Bytes.toBytes("anotherrow");
-  private static final byte[] QUALIFIER = Bytes.toBytes("testQualifier");
-  private static final byte[] VALUE = Bytes.toBytes("testValue");
-  private static final byte[] COL_QUAL = Bytes.toBytes("f1");
-  private static final byte[] VAL_BYTES = Bytes.toBytes("v1");
-  private static final byte[] ROW_BYTES = Bytes.toBytes("r1");
-
-  @Rule
-  public TestName name = new TestName();
+public class FromClientSide3TestBase {
+
+  private static final Logger LOG = LoggerFactory.getLogger(FromClientSide3TestBase.class);
+  private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
+
+  private static int WAITTABLE_MILLIS;
+  private static byte[] FAMILY;
+  private static int SLAVES;
+  private static byte[] ROW;
+  private static byte[] ANOTHERROW;
+  private static byte[] QUALIFIER;
+  private static byte[] VALUE;
+  private static byte[] COL_QUAL;
+  private static byte[] VAL_BYTES;
+  private static byte[] ROW_BYTES;
+
   private TableName tableName;
 
-  /**
-   * @throws java.lang.Exception
-   */
-  @BeforeClass
-  public static void setUpBeforeClass() throws Exception {
+  protected static void startCluster() throws Exception {
+    WAITTABLE_MILLIS = 10000;
+    FAMILY = Bytes.toBytes("testFamily");
+    SLAVES = 3;
+    ROW = Bytes.toBytes("testRow");
+    ANOTHERROW = Bytes.toBytes("anotherrow");
+    QUALIFIER = Bytes.toBytes("testQualifier");
+    VALUE = Bytes.toBytes("testValue");
+    COL_QUAL = Bytes.toBytes("f1");
+    VAL_BYTES = Bytes.toBytes("v1");
+    ROW_BYTES = Bytes.toBytes("r1");
     TEST_UTIL.startMiniCluster(SLAVES);
   }
 
-  /**
-   * @throws java.lang.Exception
-   */
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception {
+  @AfterAll
+  public static void shutdownCluster() throws Exception {
     TEST_UTIL.shutdownMiniCluster();
   }
 
-  /**
-   * @throws java.lang.Exception
-   */
-  @Before
-  public void setUp() throws Exception {
-    tableName = TableName.valueOf(name.getMethodName());
+  @BeforeEach
+  public void setUp(TestInfo testInfo) throws Exception {
+    tableName = TableName.valueOf(testInfo.getTestMethod().get().getName());
   }
 
-  /**
-   * @throws java.lang.Exception
-   */
-  @After
+  @AfterEach
   public void tearDown() throws Exception {
-    for (HTableDescriptor htd : TEST_UTIL.getAdmin().listTables()) {
+    for (TableDescriptor htd : TEST_UTIL.getAdmin().listTableDescriptors()) {
       LOG.info("Tear down, remove table=" + htd.getTableName());
       TEST_UTIL.deleteTable(htd.getTableName());
     }
@@ -249,7 +232,7 @@ public class TestFromClientSide3 {
       table.put(put);
 
       Result r = table.get(new Get(row));
-      assertEquals(r.toString(), 3, r.size());
+      assertEquals(3, r.size(), r.toString());
       assertEquals("testValue", Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
       assertEquals("qual0", Bytes.toString(CellUtil.cloneValue(r.rawCells()[1])));
       assertEquals("qual1", Bytes.toString(CellUtil.cloneValue(r.rawCells()[2])));
@@ -835,8 +818,8 @@ public class TestFromClientSide3 {
     });
     service.shutdown();
     service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
-    assertEquals("The write is blocking by RegionObserver#postBatchMutate"
-      + ", so the data is invisible to reader", 0, cells.size());
+    assertEquals(0, cells.size(), "The write is blocking by RegionObserver#postBatchMutate"
+      + ", so the data is invisible to reader");
     TEST_UTIL.deleteTable(tableName);
   }
 
@@ -1074,7 +1057,7 @@ public class TestFromClientSide3 {
         for (Thread t : threads) {
           t.join();
         }
-        assertEquals("Not equal in round " + round, THREAD_NUM, successCnt.get());
+        assertEquals(THREAD_NUM, successCnt.get(), "Not equal in round " + round);
       }
       TEST_UTIL.deleteTable(tableName);
     }
@@ -1097,8 +1080,8 @@ public class TestFromClientSide3 {
     throws IOException, InterruptedException {
     HRegion region = find(tableName);
     Coprocessor cp = region.getCoprocessorHost().findCoprocessor(clz.getName());
-    assertTrue("The cp instance should be " + clz.getName() + ", current instance is "
-      + cp.getClass().getName(), clz.isInstance(cp));
+    assertTrue(clz.isInstance(cp), "The cp instance should be " + clz.getName()
+      + ", current instance is " + cp.getClass().getName());
     return clz.cast(cp);
   }
 
@@ -1200,10 +1183,10 @@ public class TestFromClientSide3 {
           list.add(result);
         }
 
-        Assert.assertEquals(5, list.stream().mapToInt(Result::size).sum());
-        Assert.assertEquals(2, list.size());
-        Assert.assertEquals(3, list.get(0).size());
-        Assert.assertEquals(2, list.get(1).size());
+        assertEquals(5, list.stream().mapToInt(Result::size).sum());
+        assertEquals(2, list.size());
+        assertEquals(3, list.get(0).size());
+        assertEquals(2, list.get(1).size());
       }
 
       scan = new Scan();
@@ -1214,11 +1197,11 @@ public class TestFromClientSide3 {
         while ((result = scanner.next()) != null) {
           list.add(result);
         }
-        Assert.assertEquals(5, list.stream().mapToInt(Result::size).sum());
-        Assert.assertEquals(3, list.size());
-        Assert.assertEquals(2, list.get(0).size());
-        Assert.assertEquals(2, list.get(1).size());
-        Assert.assertEquals(1, list.get(2).size());
+        assertEquals(5, list.stream().mapToInt(Result::size).sum());
+        assertEquals(3, list.size());
+        assertEquals(2, list.get(0).size());
+        assertEquals(2, list.get(1).size());
+        assertEquals(1, list.get(2).size());
       }
     }
   }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
index aed5ba707c0..daad7ce3188 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide3.java
@@ -17,1209 +17,17 @@
  */
 package org.apache.hadoop.hbase.client;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadLocalRandom;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hbase.Cell;
-import org.apache.hadoop.hbase.CellUtil;
-import org.apache.hadoop.hbase.Coprocessor;
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.HBaseTestingUtility;
-import org.apache.hadoop.hbase.HColumnDescriptor;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.HRegionLocation;
-import org.apache.hadoop.hbase.HTableDescriptor;
-import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.coprocessor.MultiRowMutationEndpoint;
-import org.apache.hadoop.hbase.coprocessor.ObserverContext;
-import org.apache.hadoop.hbase.coprocessor.RegionCoprocessor;
-import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
-import org.apache.hadoop.hbase.coprocessor.RegionObserver;
-import org.apache.hadoop.hbase.ipc.CoprocessorRpcUtils;
-import org.apache.hadoop.hbase.ipc.ServerRpcController;
-import org.apache.hadoop.hbase.protobuf.generated.MultiRowMutationProtos;
-import org.apache.hadoop.hbase.regionserver.HRegion;
-import org.apache.hadoop.hbase.regionserver.HRegionServer;
-import org.apache.hadoop.hbase.regionserver.MiniBatchOperationInProgress;
-import org.apache.hadoop.hbase.regionserver.RegionScanner;
 import org.apache.hadoop.hbase.testclassification.ClientTests;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
-import org.apache.hadoop.hbase.util.Pair;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.junit.rules.TestName;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
-import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
-
-@Category({ LargeTests.class, ClientTests.class })
-public class TestFromClientSide3 {
-
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE =
-    HBaseClassTestRule.forClass(TestFromClientSide3.class);
-
-  private static final Logger LOG = LoggerFactory.getLogger(TestFromClientSide3.class);
-  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
-  private static final int WAITTABLE_MILLIS = 10000;
-  private static byte[] FAMILY = Bytes.toBytes("testFamily");
-  private static int SLAVES = 3;
-  private static final byte[] ROW = Bytes.toBytes("testRow");
-  private static final byte[] ANOTHERROW = Bytes.toBytes("anotherrow");
-  private static final byte[] QUALIFIER = Bytes.toBytes("testQualifier");
-  private static final byte[] VALUE = Bytes.toBytes("testValue");
-  private static final byte[] COL_QUAL = Bytes.toBytes("f1");
-  private static final byte[] VAL_BYTES = Bytes.toBytes("v1");
-  private static final byte[] ROW_BYTES = Bytes.toBytes("r1");
-
-  @Rule
-  public TestName name = new TestName();
-  private TableName tableName;
-
-  /**
-   * @throws java.lang.Exception
-   */
-  @BeforeClass
-  public static void setUpBeforeClass() throws Exception {
-    TEST_UTIL.startMiniCluster(SLAVES);
-  }
-
-  /**
-   * @throws java.lang.Exception
-   */
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception {
-    TEST_UTIL.shutdownMiniCluster();
-  }
-
-  /**
-   * @throws java.lang.Exception
-   */
-  @Before
-  public void setUp() throws Exception {
-    tableName = TableName.valueOf(name.getMethodName());
-  }
-
-  /**
-   * @throws java.lang.Exception
-   */
-  @After
-  public void tearDown() throws Exception {
-    for (HTableDescriptor htd : TEST_UTIL.getAdmin().listTables()) {
-      LOG.info("Tear down, remove table=" + htd.getTableName());
-      TEST_UTIL.deleteTable(htd.getTableName());
-    }
-  }
-
-  private void randomCFPuts(Table table, byte[] row, byte[] family, int nPuts) throws Exception {
-    Put put = new Put(row);
-    Random rand = ThreadLocalRandom.current();
-    for (int i = 0; i < nPuts; i++) {
-      byte[] qualifier = Bytes.toBytes(rand.nextInt());
-      byte[] value = Bytes.toBytes(rand.nextInt());
-      put.addColumn(family, qualifier, value);
-    }
-    table.put(put);
-  }
-
-  private void performMultiplePutAndFlush(HBaseAdmin admin, Table table, byte[] row, byte[] family,
-    int nFlushes, int nPuts) throws Exception {
-
-    try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(table.getName())) {
-      // connection needed for poll-wait
-      HRegionLocation loc = locator.getRegionLocation(row, true);
-      AdminProtos.AdminService.BlockingInterface server =
-        ((ClusterConnection) admin.getConnection()).getAdmin(loc.getServerName());
-      byte[] regName = loc.getRegionInfo().getRegionName();
-
-      for (int i = 0; i < nFlushes; i++) {
-        randomCFPuts(table, row, family, nPuts);
-        List<String> sf = ProtobufUtil.getStoreFiles(server, regName, FAMILY);
-        int sfCount = sf.size();
-
-        admin.flush(table.getName());
-      }
-    }
-  }
-
-  private static List<Cell> toList(ResultScanner scanner) {
-    try {
-      List<Cell> cells = new ArrayList<>();
-      for (Result r : scanner) {
-        cells.addAll(r.listCells());
-      }
-      return cells;
-    } finally {
-      scanner.close();
-    }
-  }
-
-  @Test
-  public void testScanAfterDeletingSpecifiedRow() throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-      byte[] row = Bytes.toBytes("SpecifiedRow");
-      byte[] value0 = Bytes.toBytes("value_0");
-      byte[] value1 = Bytes.toBytes("value_1");
-      Put put = new Put(row);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-      Delete d = new Delete(row);
-      table.delete(d);
-      put = new Put(row);
-      put.addColumn(FAMILY, null, value0);
-      table.put(put);
-      put = new Put(row);
-      put.addColumn(FAMILY, null, value1);
-      table.put(put);
-      List<Cell> cells = toList(table.getScanner(new Scan()));
-      assertEquals(1, cells.size());
-      assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
-
-      cells = toList(table.getScanner(new Scan().addFamily(FAMILY)));
-      assertEquals(1, cells.size());
-      assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
-
-      cells = toList(table.getScanner(new Scan().addColumn(FAMILY, QUALIFIER)));
-      assertEquals(0, cells.size());
-
-      TEST_UTIL.getAdmin().flush(tableName);
-      cells = toList(table.getScanner(new Scan()));
-      assertEquals(1, cells.size());
-      assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
-
-      cells = toList(table.getScanner(new Scan().addFamily(FAMILY)));
-      assertEquals(1, cells.size());
-      assertEquals("value_1", Bytes.toString(CellUtil.cloneValue(cells.get(0))));
-
-      cells = toList(table.getScanner(new Scan().addColumn(FAMILY, QUALIFIER)));
-      assertEquals(0, cells.size());
-    }
-  }
-
-  @Test
-  public void testScanAfterDeletingSpecifiedRowV2() throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-      byte[] row = Bytes.toBytes("SpecifiedRow");
-      byte[] qual0 = Bytes.toBytes("qual0");
-      byte[] qual1 = Bytes.toBytes("qual1");
-      long now = EnvironmentEdgeManager.currentTime();
-      Delete d = new Delete(row, now);
-      table.delete(d);
-
-      Put put = new Put(row);
-      put.addColumn(FAMILY, null, now + 1, VALUE);
-      table.put(put);
-
-      put = new Put(row);
-      put.addColumn(FAMILY, qual1, now + 2, qual1);
-      table.put(put);
-
-      put = new Put(row);
-      put.addColumn(FAMILY, qual0, now + 3, qual0);
-      table.put(put);
-
-      Result r = table.get(new Get(row));
-      assertEquals(r.toString(), 3, r.size());
-      assertEquals("testValue", Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
-      assertEquals("qual0", Bytes.toString(CellUtil.cloneValue(r.rawCells()[1])));
-      assertEquals("qual1", Bytes.toString(CellUtil.cloneValue(r.rawCells()[2])));
-
-      TEST_UTIL.getAdmin().flush(tableName);
-      r = table.get(new Get(row));
-      assertEquals(3, r.size());
-      assertEquals("testValue", Bytes.toString(CellUtil.cloneValue(r.rawCells()[0])));
-      assertEquals("qual0", Bytes.toString(CellUtil.cloneValue(r.rawCells()[1])));
-      assertEquals("qual1", Bytes.toString(CellUtil.cloneValue(r.rawCells()[2])));
-    }
-  }
-
-  // override the config settings at the CF level and ensure priority
-  @Test
-  public void testAdvancedConfigOverride() throws Exception {
-    /*
-     * Overall idea: (1) create 3 store files and issue a compaction. config's compaction.min == 3,
-     * so should work. (2) Increase the compaction.min toggle in the HTD to 5 and modify table. If
-     * we use the HTD value instead of the default config value, adding 3 files and issuing a
-     * compaction SHOULD NOT work (3) Decrease the compaction.min toggle in the HCD to 2 and modify
-     * table. The CF schema should override the Table schema and now cause a minor compaction.
-     */
-    TEST_UTIL.getConfiguration().setInt("hbase.hstore.compaction.min", 3);
-
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-      try (Admin admin = TEST_UTIL.getAdmin()) {
-        ClusterConnection connection = (ClusterConnection) TEST_UTIL.getConnection();
-
-        // Create 3 store files.
-        byte[] row = Bytes.toBytes(ThreadLocalRandom.current().nextInt());
-        performMultiplePutAndFlush((HBaseAdmin) admin, table, row, FAMILY, 3, 100);
-
-        try (RegionLocator locator = TEST_UTIL.getConnection().getRegionLocator(tableName)) {
-          // Verify we have multiple store files.
-          HRegionLocation loc = locator.getRegionLocation(row, true);
-          byte[] regionName = loc.getRegionInfo().getRegionName();
-          AdminProtos.AdminService.BlockingInterface server =
-            connection.getAdmin(loc.getServerName());
-          assertTrue(ProtobufUtil.getStoreFiles(server, regionName, FAMILY).size() > 1);
-
-          // Issue a compaction request
-          admin.compact(tableName);
-
-          // poll wait for the compactions to happen
-          for (int i = 0; i < 10 * 1000 / 40; ++i) {
-            // The number of store files after compaction should be lesser.
-            loc = locator.getRegionLocation(row, true);
-            if (!loc.getRegionInfo().isOffline()) {
-              regionName = loc.getRegionInfo().getRegionName();
-              server = connection.getAdmin(loc.getServerName());
-              if (ProtobufUtil.getStoreFiles(server, regionName, FAMILY).size() <= 1) {
-                break;
-              }
-            }
-            Thread.sleep(40);
-          }
-          // verify the compactions took place and that we didn't just time out
-          assertTrue(ProtobufUtil.getStoreFiles(server, regionName, FAMILY).size() <= 1);
-
-          // change the compaction.min config option for this table to 5
-          LOG.info("hbase.hstore.compaction.min should now be 5");
-          HTableDescriptor htd = new HTableDescriptor(table.getTableDescriptor());
-          htd.setValue("hbase.hstore.compaction.min", String.valueOf(5));
-          admin.modifyTable(tableName, htd);
-          Pair<Integer, Integer> st = admin.getAlterStatus(tableName);
-          while (null != st && st.getFirst() > 0) {
-            LOG.debug(st.getFirst() + " regions left to update");
-            Thread.sleep(40);
-            st = admin.getAlterStatus(tableName);
-          }
-          LOG.info("alter status finished");
-
-          // Create 3 more store files.
-          performMultiplePutAndFlush((HBaseAdmin) admin, table, row, FAMILY, 3, 10);
-
-          // Issue a compaction request
-          admin.compact(tableName);
-
-          // This time, the compaction request should not happen
-          Thread.sleep(10 * 1000);
-          loc = locator.getRegionLocation(row, true);
-          regionName = loc.getRegionInfo().getRegionName();
-          server = connection.getAdmin(loc.getServerName());
-          int sfCount = ProtobufUtil.getStoreFiles(server, regionName, FAMILY).size();
-          assertTrue(sfCount > 1);
-
-          // change an individual CF's config option to 2 & online schema update
-          LOG.info("hbase.hstore.compaction.min should now be 2");
-          HColumnDescriptor hcd = new HColumnDescriptor(htd.getFamily(FAMILY));
-          hcd.setValue("hbase.hstore.compaction.min", String.valueOf(2));
-          htd.modifyFamily(hcd);
-          admin.modifyTable(tableName, htd);
-          st = admin.getAlterStatus(tableName);
-          while (null != st && st.getFirst() > 0) {
-            LOG.debug(st.getFirst() + " regions left to update");
-            Thread.sleep(40);
-            st = admin.getAlterStatus(tableName);
-          }
-          LOG.info("alter status finished");
-
-          // Issue a compaction request
-          admin.compact(tableName);
-
-          // poll wait for the compactions to happen
-          for (int i = 0; i < 10 * 1000 / 40; ++i) {
-            loc = locator.getRegionLocation(row, true);
-            regionName = loc.getRegionInfo().getRegionName();
-            try {
-              server = connection.getAdmin(loc.getServerName());
-              if (ProtobufUtil.getStoreFiles(server, regionName, FAMILY).size() < sfCount) {
-                break;
-              }
-            } catch (Exception e) {
-              LOG.debug("Waiting for region to come online: " + Bytes.toString(regionName));
-            }
-            Thread.sleep(40);
-          }
-
-          // verify the compaction took place and that we didn't just time out
-          assertTrue(ProtobufUtil.getStoreFiles(server, regionName, FAMILY).size() < sfCount);
-
-          // Finally, ensure that we can remove a custom config value after we made it
-          LOG.info("Removing CF config value");
-          LOG.info("hbase.hstore.compaction.min should now be 5");
-          hcd = new HColumnDescriptor(htd.getFamily(FAMILY));
-          hcd.setValue("hbase.hstore.compaction.min", null);
-          htd.modifyFamily(hcd);
-          admin.modifyTable(tableName, htd);
-          st = admin.getAlterStatus(tableName);
-          while (null != st && st.getFirst() > 0) {
-            LOG.debug(st.getFirst() + " regions left to update");
-            Thread.sleep(40);
-            st = admin.getAlterStatus(tableName);
-          }
-          LOG.info("alter status finished");
-          assertNull(
-            table.getTableDescriptor().getFamily(FAMILY).getValue("hbase.hstore.compaction.min"));
-        }
-      }
-    }
-  }
-
-  @Test
-  public void testHTableBatchWithEmptyPut() throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-      List actions = (List) new ArrayList();
-      Object[] results = new Object[2];
-      // create an empty Put
-      Put put1 = new Put(ROW);
-      actions.add(put1);
-
-      Put put2 = new Put(ANOTHERROW);
-      put2.addColumn(FAMILY, QUALIFIER, VALUE);
-      actions.add(put2);
-
-      table.batch(actions, results);
-      fail("Empty Put should have failed the batch call");
-    } catch (IllegalArgumentException iae) {
-    }
-  }
-
-  // Test Table.batch with large amount of mutations against the same key.
-  // It used to trigger read lock's "Maximum lock count exceeded" Error.
-  @Test
-  public void testHTableWithLargeBatch() throws IOException, InterruptedException {
-    int sixtyFourK = 64 * 1024;
-    List actions = new ArrayList();
-    Object[] results = new Object[(sixtyFourK + 1) * 2];
-
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      for (int i = 0; i < sixtyFourK + 1; i++) {
-        Put put1 = new Put(ROW);
-        put1.addColumn(FAMILY, QUALIFIER, VALUE);
-        actions.add(put1);
-
-        Put put2 = new Put(ANOTHERROW);
-        put2.addColumn(FAMILY, QUALIFIER, VALUE);
-        actions.add(put2);
-      }
-
-      table.batch(actions, results);
-    }
-  }
-
-  @Test
-  public void testBatchWithRowMutation() throws Exception {
-    LOG.info("Starting testBatchWithRowMutation");
-    byte[][] QUALIFIERS = new byte[][] { Bytes.toBytes("a"), Bytes.toBytes("b") };
-
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      RowMutations arm = RowMutations
-        .of(Collections.singletonList(new Put(ROW).addColumn(FAMILY, QUALIFIERS[0], VALUE)));
-      Object[] batchResult = new Object[1];
-      table.batch(Arrays.asList(arm), batchResult);
-
-      Get g = new Get(ROW);
-      Result r = table.get(g);
-      assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[0])));
-
-      arm = RowMutations.of(Arrays.asList(new Put(ROW).addColumn(FAMILY, QUALIFIERS[1], VALUE),
-        new Delete(ROW).addColumns(FAMILY, QUALIFIERS[0])));
-      table.batch(Arrays.asList(arm), batchResult);
-      r = table.get(g);
-      assertEquals(0, Bytes.compareTo(VALUE, r.getValue(FAMILY, QUALIFIERS[1])));
-      assertNull(r.getValue(FAMILY, QUALIFIERS[0]));
-
-      // Test that we get the correct remote exception for RowMutations from batch()
-      try {
-        arm = RowMutations.of(Collections.singletonList(
-          new Put(ROW).addColumn(new byte[] { 'b', 'o', 'g', 'u', 's' }, QUALIFIERS[0], VALUE)));
-        table.batch(Arrays.asList(arm), batchResult);
-        fail("Expected RetriesExhaustedWithDetailsException with NoSuchColumnFamilyException");
-      } catch (RetriesExhaustedWithDetailsException e) {
-        String msg = e.getMessage();
-        assertTrue(msg.contains("NoSuchColumnFamilyException"));
-      }
-    }
-  }
-
-  @Test
-  public void testBatchWithCheckAndMutate() throws Exception {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      byte[] row1 = Bytes.toBytes("row1");
-      byte[] row2 = Bytes.toBytes("row2");
-      byte[] row3 = Bytes.toBytes("row3");
-      byte[] row4 = Bytes.toBytes("row4");
-      byte[] row5 = Bytes.toBytes("row5");
-      byte[] row6 = Bytes.toBytes("row6");
-      byte[] row7 = Bytes.toBytes("row7");
-
-      table
-        .put(Arrays.asList(new Put(row1).addColumn(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a")),
-          new Put(row2).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")),
-          new Put(row3).addColumn(FAMILY, Bytes.toBytes("C"), Bytes.toBytes("c")),
-          new Put(row4).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d")),
-          new Put(row5).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("e")),
-          new Put(row6).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes(10L)),
-          new Put(row7).addColumn(FAMILY, Bytes.toBytes("G"), Bytes.toBytes("g"))));
-
-      CheckAndMutate checkAndMutate1 =
-        CheckAndMutate.newBuilder(row1).ifEquals(FAMILY, Bytes.toBytes("A"), Bytes.toBytes("a"))
-          .build(new RowMutations(row1)
-            .add((Mutation) new Put(row1).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("g")))
-            .add((Mutation) new Delete(row1).addColumns(FAMILY, Bytes.toBytes("A")))
-            .add(new Increment(row1).addColumn(FAMILY, Bytes.toBytes("C"), 3L))
-            .add(new Append(row1).addColumn(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("d"))));
-      Get get = new Get(row2).addColumn(FAMILY, Bytes.toBytes("B"));
-      RowMutations mutations = new RowMutations(row3)
-        .add((Mutation) new Delete(row3).addColumns(FAMILY, Bytes.toBytes("C")))
-        .add((Mutation) new Put(row3).addColumn(FAMILY, Bytes.toBytes("F"), Bytes.toBytes("f")))
-        .add(new Increment(row3).addColumn(FAMILY, Bytes.toBytes("A"), 5L))
-        .add(new Append(row3).addColumn(FAMILY, Bytes.toBytes("B"), Bytes.toBytes("b")));
-      CheckAndMutate checkAndMutate2 =
-        CheckAndMutate.newBuilder(row4).ifEquals(FAMILY, Bytes.toBytes("D"), Bytes.toBytes("a"))
-          .build(new Put(row4).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("h")));
-      Put put = new Put(row5).addColumn(FAMILY, Bytes.toBytes("E"), Bytes.toBytes("f"));
-      CheckAndMutate checkAndMutate3 =
-        CheckAndMutate.newBuilder(row6).ifEquals(FAMILY, Bytes.toBytes("F"), Bytes.toBytes(10L))
-          .build(new Increment(row6).addColumn(FAMILY, Bytes.toBytes("F"), 1));
-      CheckAndMutate checkAndMutate4 =
-        CheckAndMutate.newBuilder(row7).ifEquals(FAMILY, Bytes.toBytes("G"), Bytes.toBytes("g"))
-          .build(new Append(row7).addColumn(FAMILY, Bytes.toBytes("G"), Bytes.toBytes("g")));
-
-      List<Row> actions = Arrays.asList(checkAndMutate1, get, mutations, checkAndMutate2, put,
-        checkAndMutate3, checkAndMutate4);
-      Object[] results = new Object[actions.size()];
-      table.batch(actions, results);
-
-      CheckAndMutateResult checkAndMutateResult = (CheckAndMutateResult) results[0];
-      assertTrue(checkAndMutateResult.isSuccess());
-      assertEquals(3L,
-        Bytes.toLong(checkAndMutateResult.getResult().getValue(FAMILY, Bytes.toBytes("C"))));
-      assertEquals("d",
-        Bytes.toString(checkAndMutateResult.getResult().getValue(FAMILY, Bytes.toBytes("D"))));
-
-      assertEquals("b", Bytes.toString(((Result) results[1]).getValue(FAMILY, Bytes.toBytes("B"))));
-
-      Result result = (Result) results[2];
-      assertTrue(result.getExists());
-      assertEquals(5L, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("A"))));
-      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
-
-      checkAndMutateResult = (CheckAndMutateResult) results[3];
-      assertFalse(checkAndMutateResult.isSuccess());
-      assertNull(checkAndMutateResult.getResult());
-
-      assertTrue(((Result) results[4]).isEmpty());
-
-      checkAndMutateResult = (CheckAndMutateResult) results[5];
-      assertTrue(checkAndMutateResult.isSuccess());
-      assertEquals(11,
-        Bytes.toLong(checkAndMutateResult.getResult().getValue(FAMILY, Bytes.toBytes("F"))));
-
-      checkAndMutateResult = (CheckAndMutateResult) results[6];
-      assertTrue(checkAndMutateResult.isSuccess());
-      assertEquals("gg",
-        Bytes.toString(checkAndMutateResult.getResult().getValue(FAMILY, Bytes.toBytes("G"))));
-
-      result = table.get(new Get(row1));
-      assertEquals("g", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
-      assertNull(result.getValue(FAMILY, Bytes.toBytes("A")));
-      assertEquals(3L, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("C"))));
-      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
-
-      result = table.get(new Get(row3));
-      assertNull(result.getValue(FAMILY, Bytes.toBytes("C")));
-      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("F"))));
-      assertNull(Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("C"))));
-      assertEquals(5L, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("A"))));
-      assertEquals("b", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("B"))));
-
-      result = table.get(new Get(row4));
-      assertEquals("d", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("D"))));
-
-      result = table.get(new Get(row5));
-      assertEquals("f", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("E"))));
-
-      result = table.get(new Get(row6));
-      assertEquals(11, Bytes.toLong(result.getValue(FAMILY, Bytes.toBytes("F"))));
-
-      result = table.get(new Get(row7));
-      assertEquals("gg", Bytes.toString(result.getValue(FAMILY, Bytes.toBytes("G"))));
-    }
-  }
-
-  @Test
-  public void testHTableExistsMethodSingleRegionSingleGet()
-    throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      // Test with a single region table.
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-
-      Get get = new Get(ROW);
-
-      boolean exist = table.exists(get);
-      assertFalse(exist);
-
-      table.put(put);
-
-      exist = table.exists(get);
-      assertTrue(exist);
-    }
-  }
-
-  @Test
-  public void testHTableExistsMethodSingleRegionMultipleGets()
-    throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-
-      List<Get> gets = new ArrayList<>();
-      gets.add(new Get(ROW));
-      gets.add(new Get(ANOTHERROW));
-
-      boolean[] results = table.exists(gets);
-      assertTrue(results[0]);
-      assertFalse(results[1]);
-    }
-  }
-
-  @Test
-  public void testHTableExistsBeforeGet() throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-
-      Get get = new Get(ROW);
-
-      boolean exist = table.exists(get);
-      assertEquals(true, exist);
-
-      Result result = table.get(get);
-      assertEquals(false, result.isEmpty());
-      assertTrue(Bytes.equals(VALUE, result.getValue(FAMILY, QUALIFIER)));
-    }
-  }
-
-  @Test
-  public void testHTableExistsAllBeforeGet() throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      final byte[] ROW2 = Bytes.add(ROW, Bytes.toBytes("2"));
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-      put = new Put(ROW2);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-
-      Get get = new Get(ROW);
-      Get get2 = new Get(ROW2);
-      ArrayList<Get> getList = new ArrayList(2);
-      getList.add(get);
-      getList.add(get2);
-
-      boolean[] exists = table.existsAll(getList);
-      assertEquals(true, exists[0]);
-      assertEquals(true, exists[1]);
-
-      Result[] result = table.get(getList);
-      assertEquals(false, result[0].isEmpty());
-      assertTrue(Bytes.equals(VALUE, result[0].getValue(FAMILY, QUALIFIER)));
-      assertEquals(false, result[1].isEmpty());
-      assertTrue(Bytes.equals(VALUE, result[1].getValue(FAMILY, QUALIFIER)));
-    }
-  }
-
-  @Test
-  public void testHTableExistsMethodMultipleRegionsSingleGet() throws Exception {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY }, 1,
-      new byte[] { 0x00 }, new byte[] { (byte) 0xff }, 255)) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-
-      Get get = new Get(ROW);
-
-      boolean exist = table.exists(get);
-      assertFalse(exist);
-
-      table.put(put);
-
-      exist = table.exists(get);
-      assertTrue(exist);
-    }
-  }
-
-  @Test
-  public void testHTableExistsMethodMultipleRegionsMultipleGets() throws Exception {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY }, 1,
-      new byte[] { 0x00 }, new byte[] { (byte) 0xff }, 255)) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-
-      List<Get> gets = new ArrayList<>();
-      gets.add(new Get(ANOTHERROW));
-      gets.add(new Get(Bytes.add(ROW, new byte[] { 0x00 })));
-      gets.add(new Get(ROW));
-      gets.add(new Get(Bytes.add(ANOTHERROW, new byte[] { 0x00 })));
-
-      LOG.info("Calling exists");
-      boolean[] results = table.existsAll(gets);
-      assertFalse(results[0]);
-      assertFalse(results[1]);
-      assertTrue(results[2]);
-      assertFalse(results[3]);
-
-      // Test with the first region.
-      put = new Put(new byte[] { 0x00 });
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-
-      gets = new ArrayList<>();
-      gets.add(new Get(new byte[] { 0x00 }));
-      gets.add(new Get(new byte[] { 0x00, 0x00 }));
-      results = table.existsAll(gets);
-      assertTrue(results[0]);
-      assertFalse(results[1]);
-
-      // Test with the last region
-      put = new Put(new byte[] { (byte) 0xff, (byte) 0xff });
-      put.addColumn(FAMILY, QUALIFIER, VALUE);
-      table.put(put);
-
-      gets = new ArrayList<>();
-      gets.add(new Get(new byte[] { (byte) 0xff }));
-      gets.add(new Get(new byte[] { (byte) 0xff, (byte) 0xff }));
-      gets.add(new Get(new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff }));
-      results = table.existsAll(gets);
-      assertFalse(results[0]);
-      assertTrue(results[1]);
-      assertFalse(results[2]);
-    }
-  }
-
-  @Test
-  public void testGetEmptyRow() throws Exception {
-    // Create a table and put in 1 row
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      Put put = new Put(ROW_BYTES);
-      put.addColumn(FAMILY, COL_QUAL, VAL_BYTES);
-      table.put(put);
-
-      // Try getting the row with an empty row key
-      Result res = null;
-      try {
-        res = table.get(new Get(new byte[0]));
-        fail();
-      } catch (IllegalArgumentException e) {
-        // Expected.
-      }
-      assertTrue(res == null);
-      res = table.get(new Get(Bytes.toBytes("r1-not-exist")));
-      assertTrue(res.isEmpty() == true);
-      res = table.get(new Get(ROW_BYTES));
-      assertTrue(Arrays.equals(res.getValue(FAMILY, COL_QUAL), VAL_BYTES));
-    }
-  }
-
-  @Test
-  public void testConnectionDefaultUsesCodec() throws Exception {
-    ClusterConnection con = (ClusterConnection) TEST_UTIL.getConnection();
-    assertTrue(con.hasCellBlockSupport());
-  }
-
-  @Test
-  public void testPutWithPreBatchMutate() throws Exception {
-    testPreBatchMutate(tableName, () -> {
-      try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
-        Put put = new Put(ROW);
-        put.addColumn(FAMILY, QUALIFIER, VALUE);
-        t.put(put);
-      } catch (IOException ex) {
-        throw new RuntimeException(ex);
-      }
-    });
-  }
-
-  @Test
-  public void testRowMutationsWithPreBatchMutate() throws Exception {
-    testPreBatchMutate(tableName, () -> {
-      try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
-        RowMutations rm = new RowMutations(ROW, 1);
-        Put put = new Put(ROW);
-        put.addColumn(FAMILY, QUALIFIER, VALUE);
-        rm.add(put);
-        t.mutateRow(rm);
-      } catch (IOException ex) {
-        throw new RuntimeException(ex);
-      }
-    });
-  }
-
-  private void testPreBatchMutate(TableName tableName, Runnable rn) throws Exception {
-    HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addCoprocessor(WaitingForScanObserver.class.getName());
-    desc.addFamily(new HColumnDescriptor(FAMILY));
-    TEST_UTIL.getAdmin().createTable(desc);
-    // Don't use waitTableAvailable(), because the scanner will mess up the co-processor
-
-    ExecutorService service = Executors.newFixedThreadPool(2);
-    service.execute(rn);
-    final List<Cell> cells = new ArrayList<>();
-    service.execute(() -> {
-      try {
-        // waiting for update.
-        TimeUnit.SECONDS.sleep(3);
-        try (Table t = TEST_UTIL.getConnection().getTable(tableName)) {
-          Scan scan = new Scan();
-          try (ResultScanner scanner = t.getScanner(scan)) {
-            for (Result r : scanner) {
-              cells.addAll(Arrays.asList(r.rawCells()));
-            }
-          }
-        }
-      } catch (IOException | InterruptedException ex) {
-        throw new RuntimeException(ex);
-      }
-    });
-    service.shutdown();
-    service.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
-    assertEquals("The write is blocking by RegionObserver#postBatchMutate"
-      + ", so the data is invisible to reader", 0, cells.size());
-    TEST_UTIL.deleteTable(tableName);
-  }
-
-  @Test
-  public void testLockLeakWithDelta() throws Exception, Throwable {
-    HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addCoprocessor(WaitingForMultiMutationsObserver.class.getName());
-    desc.setConfiguration("hbase.rowlock.wait.duration", String.valueOf(5000));
-    desc.addFamily(new HColumnDescriptor(FAMILY));
-    TEST_UTIL.getAdmin().createTable(desc);
-    TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-    // new a connection for lower retry number.
-    Configuration copy = new Configuration(TEST_UTIL.getConfiguration());
-    copy.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2);
-    try (Connection con = ConnectionFactory.createConnection(copy)) {
-      HRegion region = (HRegion) find(tableName);
-      region.setTimeoutForWriteLock(10);
-      ExecutorService putService = Executors.newSingleThreadExecutor();
-      putService.execute(() -> {
-        try (Table table = con.getTable(tableName)) {
-          Put put = new Put(ROW);
-          put.addColumn(FAMILY, QUALIFIER, VALUE);
-          // the put will be blocked by WaitingForMultiMutationsObserver.
-          table.put(put);
-        } catch (IOException ex) {
-          throw new RuntimeException(ex);
-        }
-      });
-      ExecutorService appendService = Executors.newSingleThreadExecutor();
-      appendService.execute(() -> {
-        Append append = new Append(ROW);
-        append.addColumn(FAMILY, QUALIFIER, VALUE);
-        try (Table table = con.getTable(tableName)) {
-          table.append(append);
-          fail("The APPEND should fail because the target lock is blocked by previous put");
-        } catch (Exception ex) {
-        }
-      });
-      appendService.shutdown();
-      appendService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
-      WaitingForMultiMutationsObserver observer =
-        find(tableName, WaitingForMultiMutationsObserver.class);
-      observer.latch.countDown();
-      putService.shutdown();
-      putService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
-      try (Table table = con.getTable(tableName)) {
-        Result r = table.get(new Get(ROW));
-        assertFalse(r.isEmpty());
-        assertTrue(Bytes.equals(r.getValue(FAMILY, QUALIFIER), VALUE));
-      }
-    }
-    HRegion region = (HRegion) find(tableName);
-    int readLockCount = region.getReadLockCount();
-    LOG.info("readLockCount:" + readLockCount);
-    assertEquals(0, readLockCount);
-  }
-
-  @Test
-  public void testMultiRowMutations() throws Exception, Throwable {
-    HTableDescriptor desc = new HTableDescriptor(tableName);
-    desc.addCoprocessor(MultiRowMutationEndpoint.class.getName());
-    desc.addCoprocessor(WaitingForMultiMutationsObserver.class.getName());
-    desc.setConfiguration("hbase.rowlock.wait.duration", String.valueOf(5000));
-    desc.addFamily(new HColumnDescriptor(FAMILY));
-    TEST_UTIL.getAdmin().createTable(desc);
-    TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-    // new a connection for lower retry number.
-    Configuration copy = new Configuration(TEST_UTIL.getConfiguration());
-    copy.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 2);
-    try (Connection con = ConnectionFactory.createConnection(copy)) {
-      byte[] row = Bytes.toBytes("ROW-0");
-      byte[] rowLocked = Bytes.toBytes("ROW-1");
-      byte[] value0 = Bytes.toBytes("VALUE-0");
-      byte[] value1 = Bytes.toBytes("VALUE-1");
-      byte[] value2 = Bytes.toBytes("VALUE-2");
-      assertNoLocks(tableName);
-      ExecutorService putService = Executors.newSingleThreadExecutor();
-      putService.execute(() -> {
-        try (Table table = con.getTable(tableName)) {
-          Put put0 = new Put(rowLocked);
-          put0.addColumn(FAMILY, QUALIFIER, value0);
-          // the put will be blocked by WaitingForMultiMutationsObserver.
-          table.put(put0);
-        } catch (IOException ex) {
-          throw new RuntimeException(ex);
-        }
-      });
-      ExecutorService cpService = Executors.newSingleThreadExecutor();
-      cpService.execute(() -> {
-        boolean threw;
-        Put put1 = new Put(row);
-        Put put2 = new Put(rowLocked);
-        put1.addColumn(FAMILY, QUALIFIER, value1);
-        put2.addColumn(FAMILY, QUALIFIER, value2);
-        try (Table table = con.getTable(tableName)) {
-          MultiRowMutationProtos.MutateRowsRequest request =
-            MultiRowMutationProtos.MutateRowsRequest.newBuilder()
-              .addMutationRequest(org.apache.hadoop.hbase.protobuf.ProtobufUtil.toMutation(
-                org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType.PUT,
-                put1))
-              .addMutationRequest(org.apache.hadoop.hbase.protobuf.ProtobufUtil.toMutation(
-                org.apache.hadoop.hbase.protobuf.generated.ClientProtos.MutationProto.MutationType.PUT,
-                put2))
-              .build();
-          table.coprocessorService(MultiRowMutationProtos.MultiRowMutationService.class, ROW, ROW,
-            (MultiRowMutationProtos.MultiRowMutationService exe) -> {
-              ServerRpcController controller = new ServerRpcController();
-              CoprocessorRpcUtils.BlockingRpcCallback<
-                MultiRowMutationProtos.MutateRowsResponse> rpcCallback =
-                  new CoprocessorRpcUtils.BlockingRpcCallback<>();
-              exe.mutateRows(controller, request, rpcCallback);
-              return rpcCallback.get();
-            });
-          threw = false;
-        } catch (Throwable ex) {
-          threw = true;
-        }
-        if (!threw) {
-          // Can't call fail() earlier because the catch would eat it.
-          fail("This cp should fail because the target lock is blocked by previous put");
-        }
-      });
-      cpService.shutdown();
-      cpService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
-      WaitingForMultiMutationsObserver observer =
-        find(tableName, WaitingForMultiMutationsObserver.class);
-      observer.latch.countDown();
-      putService.shutdown();
-      putService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
-      try (Table table = con.getTable(tableName)) {
-        Get g0 = new Get(row);
-        Get g1 = new Get(rowLocked);
-        Result r0 = table.get(g0);
-        Result r1 = table.get(g1);
-        assertTrue(r0.isEmpty());
-        assertFalse(r1.isEmpty());
-        assertTrue(Bytes.equals(r1.getValue(FAMILY, QUALIFIER), value0));
-      }
-      assertNoLocks(tableName);
-    }
-  }
-
-  /**
-   * A test case for issue HBASE-17482 After combile seqid with mvcc readpoint, seqid/mvcc is
-   * acquired and stamped onto cells in the append thread, a countdown latch is used to ensure that
-   * happened before cells can be put into memstore. But the MVCCPreAssign patch(HBASE-16698) make
-   * the seqid/mvcc acquirement in handler thread and stamping in append thread No countdown latch
-   * to assure cells in memstore are stamped with seqid/mvcc. If cells without mvcc(A.K.A mvcc=0)
-   * are put into memstore, then a scanner with a smaller readpoint can see these data, which
-   * disobey the multi version concurrency control rules. This test case is to reproduce this
-   * scenario.
-   */
-  @Test
-  public void testMVCCUsingMVCCPreAssign() throws IOException, InterruptedException {
-    try (Table table = TEST_UTIL.createTable(tableName, new byte[][] { FAMILY })) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-      // put two row first to init the scanner
-      Put put = new Put(Bytes.toBytes("0"));
-      put.addColumn(FAMILY, Bytes.toBytes(""), Bytes.toBytes("0"));
-      table.put(put);
-      put = new Put(Bytes.toBytes("00"));
-      put.addColumn(FAMILY, Bytes.toBytes(""), Bytes.toBytes("0"));
-      table.put(put);
-      Scan scan = new Scan();
-      scan.setTimeRange(0, Long.MAX_VALUE);
-      scan.setCaching(1);
-      ResultScanner scanner = table.getScanner(scan);
-      int rowNum = scanner.next() != null ? 1 : 0;
-      // the started scanner shouldn't see the rows put below
-      for (int i = 1; i < 1000; i++) {
-        put = new Put(Bytes.toBytes(String.valueOf(i)));
-        put.setDurability(Durability.ASYNC_WAL);
-        put.addColumn(FAMILY, Bytes.toBytes(""), Bytes.toBytes(i));
-        table.put(put);
-      }
-      for (Result result : scanner) {
-        rowNum++;
-      }
-      // scanner should only see two rows
-      assertEquals(2, rowNum);
-      scanner = table.getScanner(scan);
-      rowNum = 0;
-      for (Result result : scanner) {
-        rowNum++;
-      }
-      // the new scanner should see all rows
-      assertEquals(1001, rowNum);
-    }
-  }
-
-  @Test
-  public void testPutThenGetWithMultipleThreads() throws Exception {
-    final int THREAD_NUM = 20;
-    final int ROUND_NUM = 10;
-    for (int round = 0; round < ROUND_NUM; round++) {
-      ArrayList<Thread> threads = new ArrayList<>(THREAD_NUM);
-      final AtomicInteger successCnt = new AtomicInteger(0);
-      try (Table ht = TEST_UTIL.createTable(tableName, FAMILY)) {
-        TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-        for (int i = 0; i < THREAD_NUM; i++) {
-          final int index = i;
-          Thread t = new Thread(new Runnable() {
-
-            @Override
-            public void run() {
-              final byte[] row = Bytes.toBytes("row-" + index);
-              final byte[] value = Bytes.toBytes("v" + index);
-              try {
-                Put put = new Put(row);
-                put.addColumn(FAMILY, QUALIFIER, value);
-                ht.put(put);
-                Get get = new Get(row);
-                Result result = ht.get(get);
-                byte[] returnedValue = result.getValue(FAMILY, QUALIFIER);
-                if (Bytes.equals(value, returnedValue)) {
-                  successCnt.getAndIncrement();
-                } else {
-                  LOG.error("Should be equal but not, original value: " + Bytes.toString(value)
-                    + ", returned value: "
-                    + (returnedValue == null ? "null" : Bytes.toString(returnedValue)));
-                }
-              } catch (Throwable e) {
-                // do nothing
-              }
-            }
-          });
-          threads.add(t);
-        }
-        for (Thread t : threads) {
-          t.start();
-        }
-        for (Thread t : threads) {
-          t.join();
-        }
-        assertEquals("Not equal in round " + round, THREAD_NUM, successCnt.get());
-      }
-      TEST_UTIL.deleteTable(tableName);
-    }
-  }
-
-  private static void assertNoLocks(final TableName tableName)
-    throws IOException, InterruptedException {
-    HRegion region = (HRegion) find(tableName);
-    assertEquals(0, region.getLockedRows().size());
-  }
-
-  private static HRegion find(final TableName tableName) throws IOException, InterruptedException {
-    HRegionServer rs = TEST_UTIL.getRSForFirstRegionInTable(tableName);
-    List<HRegion> regions = rs.getRegions(tableName);
-    assertEquals(1, regions.size());
-    return regions.get(0);
-  }
-
-  private static <T extends RegionObserver> T find(final TableName tableName, Class<T> clz)
-    throws IOException, InterruptedException {
-    HRegion region = find(tableName);
-    Coprocessor cp = region.getCoprocessorHost().findCoprocessor(clz.getName());
-    assertTrue("The cp instance should be " + clz.getName() + ", current instance is "
-      + cp.getClass().getName(), clz.isInstance(cp));
-    return clz.cast(cp);
-  }
-
-  public static class WaitingForMultiMutationsObserver
-    implements RegionCoprocessor, RegionObserver {
-    final CountDownLatch latch = new CountDownLatch(1);
-
-    @Override
-    public Optional<RegionObserver> getRegionObserver() {
-      return Optional.of(this);
-    }
-
-    @Override
-    public void postBatchMutate(final ObserverContext<RegionCoprocessorEnvironment> c,
-      final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
-      try {
-        latch.await();
-      } catch (InterruptedException ex) {
-        throw new IOException(ex);
-      }
-    }
-  }
-
-  public static class WaitingForScanObserver implements RegionCoprocessor, RegionObserver {
-    private final CountDownLatch latch = new CountDownLatch(1);
-
-    @Override
-    public Optional<RegionObserver> getRegionObserver() {
-      return Optional.of(this);
-    }
-
-    @Override
-    public void postBatchMutate(final ObserverContext<RegionCoprocessorEnvironment> c,
-      final MiniBatchOperationInProgress<Mutation> miniBatchOp) throws IOException {
-      try {
-        // waiting for scanner
-        latch.await();
-      } catch (InterruptedException ex) {
-        throw new IOException(ex);
-      }
-    }
-
-    @Override
-    public RegionScanner postScannerOpen(final ObserverContext<RegionCoprocessorEnvironment> e,
-      final Scan scan, final RegionScanner s) throws IOException {
-      latch.countDown();
-      return s;
-    }
-  }
-
-  static byte[] generateHugeValue(int size) {
-    Random rand = ThreadLocalRandom.current();
-    byte[] value = new byte[size];
-    for (int i = 0; i < value.length; i++) {
-      value[i] = (byte) rand.nextInt(256);
-    }
-    return value;
-  }
-
-  @Test
-  public void testScanWithBatchSizeReturnIncompleteCells()
-    throws IOException, InterruptedException {
-    TableDescriptor hd = TableDescriptorBuilder.newBuilder(tableName)
-      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(FAMILY).setMaxVersions(3).build())
-      .build();
-    try (Table table = TEST_UTIL.createTable(hd, null)) {
-      TEST_UTIL.waitTableAvailable(tableName, WAITTABLE_MILLIS);
-
-      Put put = new Put(ROW);
-      put.addColumn(FAMILY, Bytes.toBytes(0), generateHugeValue(3 * 1024 * 1024));
-      table.put(put);
-
-      put = new Put(ROW);
-      put.addColumn(FAMILY, Bytes.toBytes(1), generateHugeValue(4 * 1024 * 1024));
-      table.put(put);
-
-      for (int i = 2; i < 5; i++) {
-        for (int version = 0; version < 2; version++) {
-          put = new Put(ROW);
-          put.addColumn(FAMILY, Bytes.toBytes(i), generateHugeValue(1024));
-          table.put(put);
-        }
-      }
-
-      Scan scan = new Scan();
-      scan.withStartRow(ROW).withStopRow(ROW, true).addFamily(FAMILY).setBatch(3)
-        .setMaxResultSize(4 * 1024 * 1024);
-      Result result;
-      try (ResultScanner scanner = table.getScanner(scan)) {
-        List<Result> list = new ArrayList<>();
-        /*
-         * The first scan rpc should return a result with 2 cells, because 3MB + 4MB > 4MB; The
-         * second scan rpc should return a result with 3 cells, because reach the batch limit = 3;
-         * The mayHaveMoreCellsInRow in last result should be false in the scan rpc. BTW, the
-         * moreResultsInRegion also would be false. Finally, the client should collect all the cells
-         * into two result: 2+3 -> 3+2;
-         */
-        while ((result = scanner.next()) != null) {
-          list.add(result);
-        }
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
 
-        Assert.assertEquals(5, list.stream().mapToInt(Result::size).sum());
-        Assert.assertEquals(2, list.size());
-        Assert.assertEquals(3, list.get(0).size());
-        Assert.assertEquals(2, list.get(1).size());
-      }
+@Tag(LargeTests.TAG)
+@Tag(ClientTests.TAG)
+public class TestFromClientSide3 extends FromClientSide3TestBase {
 
-      scan = new Scan();
-      scan.withStartRow(ROW).withStopRow(ROW, true).addFamily(FAMILY).setBatch(2)
-        .setMaxResultSize(4 * 1024 * 1024);
-      try (ResultScanner scanner = table.getScanner(scan)) {
-        List<Result> list = new ArrayList<>();
-        while ((result = scanner.next()) != null) {
-          list.add(result);
-        }
-        Assert.assertEquals(5, list.stream().mapToInt(Result::size).sum());
-        Assert.assertEquals(3, list.size());
-        Assert.assertEquals(2, list.get(0).size());
-        Assert.assertEquals(2, list.get(1).size());
-        Assert.assertEquals(1, list.get(2).size());
-      }
-    }
+  @BeforeAll
+  public static void setUpBeforeAll() throws Exception {
+    startCluster();
   }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestScannersFromClientSide.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestScannersFromClientSide.java
index 3cc454a8642..57e21b05e1e 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestScannersFromClientSide.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestScannersFromClientSide.java
@@ -18,7 +18,7 @@
 package org.apache.hadoop.hbase.client;
 
 import static org.apache.hadoop.hbase.HConstants.RPC_CODEC_CONF_KEY;
-import static org.apache.hadoop.hbase.client.TestFromClientSide3.generateHugeValue;
+import static org.apache.hadoop.hbase.client.FromClientSide3TestBase.generateHugeValue;
 import static org.apache.hadoop.hbase.ipc.RpcClient.DEFAULT_CODEC_CLASS;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/TestProtobufRpcServiceImpl.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/TestProtobufRpcServiceImpl.java
index b2ac0a3deb9..c38828fa10d 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/TestProtobufRpcServiceImpl.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/ipc/TestProtobufRpcServiceImpl.java
@@ -21,6 +21,9 @@ import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellScanner;
 import org.apache.hadoop.hbase.CellUtil;
@@ -31,7 +34,9 @@ import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.util.Threads;
 import org.apache.yetus.audience.InterfaceAudience;
 
+import org.apache.hbase.thirdparty.com.google.common.util.concurrent.ThreadFactoryBuilder;
 import org.apache.hbase.thirdparty.com.google.protobuf.BlockingService;
+import org.apache.hbase.thirdparty.com.google.protobuf.RpcCallback;
 import org.apache.hbase.thirdparty.com.google.protobuf.RpcController;
 import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
 
@@ -46,7 +51,7 @@ import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestRpcServiceProto
 import org.apache.hadoop.hbase.shaded.ipc.protobuf.generated.TestRpcServiceProtos.TestProtobufRpcProto.Interface;
 
 @InterfaceAudience.Private
-public class TestProtobufRpcServiceImpl implements BlockingInterface {
+public class TestProtobufRpcServiceImpl implements BlockingInterface, Interface {
 
   public static final BlockingService SERVICE =
     TestProtobufRpcProto.newReflectiveBlockingService(new TestProtobufRpcServiceImpl());
@@ -119,4 +124,63 @@ public class TestProtobufRpcServiceImpl implements BlockingInterface {
     return AddrResponseProto.newBuilder()
       .setAddr(RpcServer.getRemoteAddress().get().getHostAddress()).build();
   }
+
+  @Override
+  public void ping(RpcController controller, EmptyRequestProto request,
+    RpcCallback<EmptyResponseProto> done) {
+    done.run(EmptyResponseProto.getDefaultInstance());
+  }
+
+  @Override
+  public void echo(RpcController controller, EchoRequestProto request,
+    RpcCallback<EchoResponseProto> done) {
+    if (controller instanceof HBaseRpcController) {
+      HBaseRpcController pcrc = (HBaseRpcController) controller;
+      // If cells, scan them to check we are able to iterate what we were given and since this is an
+      // echo, just put them back on the controller creating a new block. Tests our block building.
+      CellScanner cellScanner = pcrc.cellScanner();
+      List<Cell> list = null;
+      if (cellScanner != null) {
+        list = new ArrayList<>();
+        try {
+          while (cellScanner.advance()) {
+            list.add(cellScanner.current());
+          }
+        } catch (IOException e) {
+          pcrc.setFailed(e);
+          return;
+        }
+      }
+      cellScanner = CellUtil.createCellScanner(list);
+      pcrc.setCellScanner(cellScanner);
+    }
+    done.run(EchoResponseProto.newBuilder().setMessage(request.getMessage()).build());
+  }
+
+  @Override
+  public void error(RpcController controller, EmptyRequestProto request,
+    RpcCallback<EmptyResponseProto> done) {
+    if (controller instanceof HBaseRpcController) {
+      ((HBaseRpcController) controller).setFailed(new DoNotRetryIOException("server error!"));
+    } else {
+      controller.setFailed("server error!");
+    }
+  }
+
+  private final ScheduledExecutorService executor =
+    Executors.newScheduledThreadPool(1, new ThreadFactoryBuilder().setDaemon(true).build());
+
+  @Override
+  public void pause(RpcController controller, PauseRequestProto request,
+    RpcCallback<EmptyResponseProto> done) {
+    executor.schedule(() -> done.run(EmptyResponseProto.getDefaultInstance()), request.getMs(),
+      TimeUnit.MILLISECONDS);
+  }
+
+  @Override
+  public void addr(RpcController controller, EmptyRequestProto request,
+    RpcCallback<AddrResponseProto> done) {
+    done.run(AddrResponseProto.newBuilder()
+      .setAddr(RpcServer.getRemoteAddress().get().getHostAddress()).build());
+  }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java
index 13b73a0d104..a00c218253a 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestRpcAccessChecks.java
@@ -22,8 +22,9 @@ import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
 
+import com.google.protobuf.RpcCallback;
+import com.google.protobuf.RpcController;
 import com.google.protobuf.Service;
 import com.google.protobuf.ServiceException;
 import java.io.IOException;
@@ -52,6 +53,12 @@ import org.apache.hadoop.hbase.coprocessor.CoprocessorHost;
 import org.apache.hadoop.hbase.coprocessor.MasterCoprocessor;
 import org.apache.hadoop.hbase.coprocessor.RegionServerCoprocessor;
 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos;
+import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.AddrResponseProto;
+import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoRequestProto;
+import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EchoResponseProto;
+import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyRequestProto;
+import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.EmptyResponseProto;
+import org.apache.hadoop.hbase.ipc.protobuf.generated.TestProtos.PauseRequestProto;
 import org.apache.hadoop.hbase.ipc.protobuf.generated.TestRpcServiceProtos;
 import org.apache.hadoop.hbase.security.AccessDeniedException;
 import org.apache.hadoop.hbase.security.User;
@@ -111,7 +118,41 @@ public class TestRpcAccessChecks {
 
     @Override
     public Iterable<Service> getServices() {
-      return Collections.singleton(mock(TestRpcServiceProtos.TestProtobufRpcProto.class));
+      return Collections.singleton(
+        TestRpcServiceProtos.TestProtobufRpcProto.newReflectiveService(new DummyService()));
+    }
+  }
+
+  private static final class DummyService
+    implements TestRpcServiceProtos.TestProtobufRpcProto.Interface {
+
+    @Override
+    public void ping(RpcController controller, EmptyRequestProto request,
+      RpcCallback<EmptyResponseProto> done) {
+
+    }
+
+    @Override
+    public void echo(RpcController controller, EchoRequestProto request,
+      RpcCallback<EchoResponseProto> done) {
+
+    }
+
+    @Override
+    public void error(RpcController controller, EmptyRequestProto request,
+      RpcCallback<EmptyResponseProto> done) {
+
+    }
+
+    @Override
+    public void pause(RpcController controller, PauseRequestProto request,
+      RpcCallback<EmptyResponseProto> done) {
+
+    }
+
+    @Override
+    public void addr(RpcController controller, EmptyRequestProto request,
+      RpcCallback<AddrResponseProto> done) {
     }
   }
 
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFromClientSide3WoUnsafe.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFromClientSide3WoUnsafe.java
index 71f3c3ee792..ffec01edafd 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFromClientSide3WoUnsafe.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/util/TestFromClientSide3WoUnsafe.java
@@ -17,31 +17,29 @@
  */
 package org.apache.hadoop.hbase.util;
 
-import org.apache.hadoop.hbase.HBaseClassTestRule;
-import org.apache.hadoop.hbase.client.TestFromClientSide3;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.mockito.Mockito.mockStatic;
+
+import org.apache.hadoop.hbase.client.FromClientSide3TestBase;
 import org.apache.hadoop.hbase.testclassification.ClientTests;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
-import org.junit.experimental.categories.Category;
-
-@Category({ LargeTests.class, ClientTests.class })
-public class TestFromClientSide3WoUnsafe extends TestFromClientSide3 {
+import org.apache.hadoop.hbase.unsafe.HBasePlatformDependent;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Tag;
+import org.mockito.MockedStatic;
 
-  @ClassRule
-  public static final HBaseClassTestRule CLASS_RULE =
-    HBaseClassTestRule.forClass(TestFromClientSide3WoUnsafe.class);
-
-  @BeforeClass
-  public static void setUpBeforeClass() throws Exception {
-    TestByteBufferUtils.disableUnsafe();
-    TestFromClientSide3.setUpBeforeClass();
-  }
+@Tag(LargeTests.TAG)
+@Tag(ClientTests.TAG)
+public class TestFromClientSide3WoUnsafe extends FromClientSide3TestBase {
 
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception {
-    TestFromClientSide3.tearDownAfterClass();
-    TestByteBufferUtils.detectAvailabilityOfUnsafe();
+  @BeforeAll
+  public static void setUpBeforeAll() throws Exception {
+    try (MockedStatic<HBasePlatformDependent> mocked = mockStatic(HBasePlatformDependent.class)) {
+      mocked.when(HBasePlatformDependent::isUnsafeAvailable).thenReturn(false);
+      mocked.when(HBasePlatformDependent::unaligned).thenReturn(false);
+      assertFalse(ByteBufferUtils.UNSAFE_AVAIL);
+      assertFalse(ByteBufferUtils.UNSAFE_UNALIGNED);
+    }
+    startCluster();
   }
 }