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 2026/05/29 10:10:00 UTC

(hbase) 01/02: Revert "HBASE-30175 Upgrade hbase-server to use junit5 Part19 (#8278)"

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

Apache9 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hbase.git

commit cc7716d3616600870819c9775686c3850d44153d
Author: Duo Zhang <zh...@apache.org>
AuthorDate: Fri May 29 18:09:13 2026 +0800

    Revert "HBASE-30175 Upgrade hbase-server to use junit5 Part19 (#8278)"
    
    This reverts commit 9742dd292f15c669a8a20e3618f73d7e09f5e863.
---
 .../TestRegisterPeerWorkerWhenRestarting.java      |  12 +-
 ...nsitPeerSyncReplicationStateProcedureRetry.java |   7 +-
 .../hbase/replication/SyncReplicationTestBase.java | 278 ++++++++++++-
 .../SyncReplicationTestBaseNoBeforeAll.java        | 304 --------------
 .../hbase/replication/TestReplicationBase.java     | 414 ++++++++++++++++++-
 .../TestReplicationBaseNoBeforeAll.java            | 438 ---------------------
 .../regionserver/TestBasicWALEntryStream.java      | 103 ++---
 .../TestBasicWALEntryStreamAsyncFSWAL.java         |  31 +-
 .../TestBasicWALEntryStreamFSHLog.java             |  31 +-
 .../TestDrainReplicationQueuesForStandBy.java      |  15 +-
 .../regionserver/TestDumpReplicationQueues.java    |  54 +--
 .../TestGlobalReplicationThrottler.java            |  37 +-
 ...InterClusterReplicationEndpointFilterEdits.java |  25 +-
 .../TestMetaRegionReplicaReplication.java          |  60 +--
 .../TestRaceWhenCreatingReplicationSource.java     |  27 +-
 .../TestRefreshPeerWhileRegionServerRestarts.java  |  15 +-
 .../TestRefreshRecoveredReplication.java           |  75 ++--
 .../regionserver/TestRegionReplicaReplication.java |  42 +-
 .../regionserver/TestReplicationCompressedWAL.java |  35 +-
 .../regionserver/TestReplicationMarker.java        |  36 +-
 .../regionserver/TestReplicationSink.java          |  48 ++-
 .../regionserver/TestReplicationSource.java        |  31 +-
 .../TestReplicationSourceLogQueue.java             |  17 +-
 .../regionserver/TestReplicationSourceManager.java |  75 ++--
 .../TestReplicationSourceManagerJoin.java          |  39 +-
 .../regionserver/TestReplicationThrottler.java     |  17 +-
 .../TestReplicationValueCompressedWAL.java         |  31 +-
 .../regionserver/TestReplicationWALEdits.java      |  31 +-
 .../replication/regionserver/TestReplicator.java   |  43 +-
 .../regionserver/TestSerialReplicationChecker.java |  40 +-
 .../TestSerialReplicationEndpoint.java             |  38 +-
 .../TestSyncReplicationShipperQuit.java            |  17 +-
 .../regionserver/TestWALEntrySinkFilter.java       |  30 +-
 .../TestWALEntryStreamCompressionReset.java        |  25 +-
 .../TestWALEntryStreamDifferentCounts.java         |  43 +-
 ...estWALEntryStreamDifferentCountsAsyncFSWAL.java |  40 +-
 .../TestWALEntryStreamDifferentCountsFSHLog.java   |  40 +-
 .../regionserver/WALEntryStreamTestBase.java       |  23 +-
 38 files changed, 1380 insertions(+), 1287 deletions(-)

diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestRegisterPeerWorkerWhenRestarting.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestRegisterPeerWorkerWhenRestarting.java
index bc628023b51..97c4ae01d2a 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestRegisterPeerWorkerWhenRestarting.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestRegisterPeerWorkerWhenRestarting.java
@@ -28,10 +28,11 @@ import org.apache.hadoop.hbase.master.HMaster;
 import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
 import org.apache.hadoop.hbase.replication.SyncReplicationState;
-import org.apache.hadoop.hbase.replication.SyncReplicationTestBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.SyncReplicationTestBase;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.testclassification.MasterTests;
 import org.apache.hadoop.hbase.util.JVMClusterUtil.MasterThread;
+import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
@@ -41,7 +42,7 @@ import org.junit.jupiter.api.Test;
  */
 @Tag(MasterTests.TAG)
 @Tag(LargeTests.TAG)
-public class TestRegisterPeerWorkerWhenRestarting extends SyncReplicationTestBaseNoBeforeAll {
+public class TestRegisterPeerWorkerWhenRestarting extends SyncReplicationTestBase {
 
   private static volatile boolean FAIL = false;
 
@@ -66,7 +67,12 @@ public class TestRegisterPeerWorkerWhenRestarting extends SyncReplicationTestBas
   @BeforeAll
   public static void setUp() throws Exception {
     UTIL2.getConfiguration().setClass(HConstants.MASTER_IMPL, HMasterForTest.class, HMaster.class);
-    startClusters();
+    SyncReplicationTestBase.setUp();
+  }
+
+  @AfterAll
+  public static void tearDown() throws Exception {
+    SyncReplicationTestBase.tearDown();
   }
 
   @Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestTransitPeerSyncReplicationStateProcedureRetry.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestTransitPeerSyncReplicationStateProcedureRetry.java
index c88ffcb4f95..d0b99d9bb65 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestTransitPeerSyncReplicationStateProcedureRetry.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/master/replication/TestTransitPeerSyncReplicationStateProcedureRetry.java
@@ -29,7 +29,7 @@ import org.apache.hadoop.hbase.procedure2.Procedure;
 import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
 import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
 import org.apache.hadoop.hbase.replication.SyncReplicationState;
-import org.apache.hadoop.hbase.replication.SyncReplicationTestBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.SyncReplicationTestBase;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.testclassification.MasterTests;
 import org.junit.jupiter.api.BeforeAll;
@@ -38,13 +38,12 @@ import org.junit.jupiter.api.Test;
 
 @Tag(MasterTests.TAG)
 @Tag(LargeTests.TAG)
-public class TestTransitPeerSyncReplicationStateProcedureRetry
-  extends SyncReplicationTestBaseNoBeforeAll {
+public class TestTransitPeerSyncReplicationStateProcedureRetry extends SyncReplicationTestBase {
 
   @BeforeAll
   public static void setUp() throws Exception {
     UTIL2.getConfiguration().setInt(MasterProcedureConstants.MASTER_PROCEDURE_THREADS, 1);
-    startClusters();
+    SyncReplicationTestBase.setUp();
   }
 
   @Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBase.java
index aee8edf8225..f0caa7a02ba 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBase.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBase.java
@@ -17,17 +17,287 @@
  */
 package org.apache.hadoop.hbase.replication;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.DoNotRetryIOException;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+import org.apache.hadoop.hbase.HBaseZKTestingUtil;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.StartTestingClusterOption;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.AsyncClusterConnection;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.master.MasterFileSystem;
+import org.apache.hadoop.hbase.protobuf.ReplicationProtobufUtil;
+import org.apache.hadoop.hbase.regionserver.HRegion;
+import org.apache.hadoop.hbase.regionserver.HRegionServer;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.FutureUtils;
+import org.apache.hadoop.hbase.wal.WAL.Entry;
+import org.apache.hadoop.hbase.wal.WALEdit;
+import org.apache.hadoop.hbase.wal.WALKeyImpl;
+import org.apache.hadoop.ipc.RemoteException;
+import org.junit.AfterClass;
 import org.junit.BeforeClass;
-import org.junit.jupiter.api.BeforeAll;
+
+import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
 
 /**
  * Base class for testing sync replication.
  */
-public class SyncReplicationTestBase extends SyncReplicationTestBaseNoBeforeAll {
+public class SyncReplicationTestBase {
+
+  protected static final HBaseZKTestingUtil ZK_UTIL = new HBaseZKTestingUtil();
+
+  protected static final HBaseTestingUtil UTIL1 = new HBaseTestingUtil();
+
+  protected static final HBaseTestingUtil UTIL2 = new HBaseTestingUtil();
+
+  protected static TableName TABLE_NAME = TableName.valueOf("SyncRep");
+
+  protected static byte[] CF = Bytes.toBytes("cf");
+
+  protected static byte[] CQ = Bytes.toBytes("cq");
+
+  protected static String PEER_ID = "1";
+
+  protected static Path REMOTE_WAL_DIR1;
+
+  protected static Path REMOTE_WAL_DIR2;
+
+  protected static void initTestingUtility(HBaseTestingUtil util, String zkParent) {
+    util.setZkCluster(ZK_UTIL.getZkCluster());
+    Configuration conf = util.getConfiguration();
+    conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, zkParent);
+    conf.setInt("replication.source.size.capacity", 102400);
+    conf.setLong("replication.source.sleepforretries", 100);
+    conf.setInt("hbase.regionserver.maxlogs", 10);
+    conf.setLong("hbase.master.logcleaner.ttl", 10);
+    conf.setInt("zookeeper.recovery.retry", 1);
+    conf.setInt("zookeeper.recovery.retry.intervalmill", 10);
+    conf.setLong(HConstants.THREAD_WAKE_FREQUENCY, 100);
+    conf.setInt("replication.stats.thread.period.seconds", 5);
+    conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
+    conf.setLong("replication.sleep.before.failover", 2000);
+    conf.setInt("replication.source.maxretriesmultiplier", 10);
+    conf.setFloat("replication.source.ratio", 1.0f);
+    conf.setBoolean("replication.source.eof.autorecovery", true);
+  }
 
-  @BeforeAll
   @BeforeClass
   public static void setUp() throws Exception {
-    startClusters();
+    ZK_UTIL.startMiniZKCluster();
+    initTestingUtility(UTIL1, "/cluster1");
+    initTestingUtility(UTIL2, "/cluster2");
+    StartTestingClusterOption option =
+      StartTestingClusterOption.builder().numMasters(2).numRegionServers(3).numDataNodes(3).build();
+    UTIL1.startMiniCluster(option);
+    UTIL2.startMiniCluster(option);
+    TableDescriptor td =
+      TableDescriptorBuilder.newBuilder(TABLE_NAME).setColumnFamily(ColumnFamilyDescriptorBuilder
+        .newBuilder(CF).setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build()).build();
+    UTIL1.getAdmin().createTable(td);
+    UTIL2.getAdmin().createTable(td);
+    FileSystem fs1 = UTIL1.getTestFileSystem();
+    FileSystem fs2 = UTIL2.getTestFileSystem();
+    REMOTE_WAL_DIR1 =
+      new Path(UTIL1.getMiniHBaseCluster().getMaster().getMasterFileSystem().getWALRootDir(),
+        "remoteWALs").makeQualified(fs1.getUri(), fs1.getWorkingDirectory());
+    REMOTE_WAL_DIR2 =
+      new Path(UTIL2.getMiniHBaseCluster().getMaster().getMasterFileSystem().getWALRootDir(),
+        "remoteWALs").makeQualified(fs2.getUri(), fs2.getWorkingDirectory());
+    UTIL1.getAdmin().addReplicationPeer(PEER_ID,
+      ReplicationPeerConfig.newBuilder().setClusterKey(UTIL2.getRpcConnnectionURI())
+        .setReplicateAllUserTables(false)
+        .setTableCFsMap(ImmutableMap.of(TABLE_NAME, new ArrayList<>()))
+        .setRemoteWALDir(REMOTE_WAL_DIR2.toUri().toString()).build());
+    UTIL2.getAdmin().addReplicationPeer(PEER_ID,
+      ReplicationPeerConfig.newBuilder().setClusterKey(UTIL1.getRpcConnnectionURI())
+        .setReplicateAllUserTables(false)
+        .setTableCFsMap(ImmutableMap.of(TABLE_NAME, new ArrayList<>()))
+        .setRemoteWALDir(REMOTE_WAL_DIR1.toUri().toString()).build());
+  }
+
+  private static void shutdown(HBaseTestingUtil util) throws Exception {
+    if (util.getHBaseCluster() == null) {
+      return;
+    }
+    Admin admin = util.getAdmin();
+    if (!admin.listReplicationPeers(Pattern.compile(PEER_ID)).isEmpty()) {
+      if (
+        admin.getReplicationPeerSyncReplicationState(PEER_ID)
+            != SyncReplicationState.DOWNGRADE_ACTIVE
+      ) {
+        admin.transitReplicationPeerSyncReplicationState(PEER_ID,
+          SyncReplicationState.DOWNGRADE_ACTIVE);
+      }
+      admin.removeReplicationPeer(PEER_ID);
+    }
+    util.shutdownMiniCluster();
+  }
+
+  @AfterClass
+  public static void tearDown() throws Exception {
+    shutdown(UTIL1);
+    shutdown(UTIL2);
+    ZK_UTIL.shutdownMiniZKCluster();
+  }
+
+  protected final void write(HBaseTestingUtil util, int start, int end) throws IOException {
+    try (Table table = util.getConnection().getTable(TABLE_NAME)) {
+      for (int i = start; i < end; i++) {
+        table.put(new Put(Bytes.toBytes(i)).addColumn(CF, CQ, Bytes.toBytes(i)));
+      }
+    }
+  }
+
+  protected final void verify(HBaseTestingUtil util, int start, int end) throws IOException {
+    try (Table table = util.getConnection().getTable(TABLE_NAME)) {
+      for (int i = start; i < end; i++) {
+        assertEquals(i, Bytes.toInt(table.get(new Get(Bytes.toBytes(i))).getValue(CF, CQ)));
+      }
+    }
+  }
+
+  protected final void verifyThroughRegion(HBaseTestingUtil util, int start, int end)
+    throws IOException {
+    HRegion region = util.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
+    for (int i = start; i < end; i++) {
+      assertEquals(i, Bytes.toInt(region.get(new Get(Bytes.toBytes(i))).getValue(CF, CQ)));
+    }
+  }
+
+  protected final void verifyNotReplicatedThroughRegion(HBaseTestingUtil util, int start, int end)
+    throws IOException {
+    HRegion region = util.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
+    for (int i = start; i < end; i++) {
+      assertTrue(region.get(new Get(Bytes.toBytes(i))).isEmpty());
+    }
+  }
+
+  protected final void waitUntilReplicationDone(HBaseTestingUtil util, int end) throws Exception {
+    // The reject check is in RSRpcService so we can still read through HRegion
+    HRegion region = util.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
+    util.waitFor(30000, new ExplainingPredicate<Exception>() {
+
+      @Override
+      public boolean evaluate() throws Exception {
+        return !region.get(new Get(Bytes.toBytes(end - 1))).isEmpty();
+      }
+
+      @Override
+      public String explainFailure() throws Exception {
+        return "Replication has not been catched up yet";
+      }
+    });
+  }
+
+  protected final void writeAndVerifyReplication(HBaseTestingUtil util1, HBaseTestingUtil util2,
+    int start, int end) throws Exception {
+    write(util1, start, end);
+    waitUntilReplicationDone(util2, end);
+    verifyThroughRegion(util2, start, end);
+  }
+
+  protected final Path getRemoteWALDir(MasterFileSystem mfs, String peerId) {
+    Path remoteWALDir = new Path(mfs.getWALRootDir(), ReplicationUtils.REMOTE_WAL_DIR_NAME);
+    return getRemoteWALDir(remoteWALDir, peerId);
+  }
+
+  protected final Path getRemoteWALDir(Path remoteWALDir, String peerId) {
+    return new Path(remoteWALDir, peerId);
+  }
+
+  protected final Path getReplayRemoteWALs(Path remoteWALDir, String peerId) {
+    return new Path(remoteWALDir, peerId + "-replay");
+  }
+
+  protected final void verifyRemovedPeer(String peerId, Path remoteWALDir, HBaseTestingUtil utility)
+    throws Exception {
+    ReplicationPeerStorage rps = ReplicationStorageFactory.getReplicationPeerStorage(
+      utility.getTestFileSystem(), utility.getZooKeeperWatcher(), utility.getConfiguration());
+    try {
+      rps.getPeerSyncReplicationState(peerId);
+      fail("Should throw exception when get the sync replication state of a removed peer.");
+    } catch (ReplicationException e) {
+      // ignore.
+    }
+    try {
+      rps.getPeerNewSyncReplicationState(peerId);
+      fail("Should throw exception when get the new sync replication state of a removed peer");
+    } catch (ReplicationException e) {
+      // ignore.
+    }
+    try (FileSystem fs = utility.getTestFileSystem()) {
+      assertFalse(fs.exists(getRemoteWALDir(remoteWALDir, peerId)));
+      assertFalse(fs.exists(getReplayRemoteWALs(remoteWALDir, peerId)));
+    }
+  }
+
+  private void assertRejection(Throwable error) {
+    assertThat(error, instanceOf(DoNotRetryIOException.class));
+    assertTrue(error.getMessage().contains("Reject to apply to sink cluster"));
+    assertTrue(error.getMessage().contains(TABLE_NAME.toString()));
+  }
+
+  protected final void verifyReplicationRequestRejection(HBaseTestingUtil utility,
+    boolean expectedRejection) throws Exception {
+    HRegionServer regionServer = utility.getRSForFirstRegionInTable(TABLE_NAME);
+    AsyncClusterConnection connection = regionServer.getAsyncClusterConnection();
+    Entry[] entries = new Entry[10];
+    for (int i = 0; i < entries.length; i++) {
+      entries[i] =
+        new Entry(new WALKeyImpl(HConstants.EMPTY_BYTE_ARRAY, TABLE_NAME, 0), new WALEdit());
+    }
+    if (!expectedRejection) {
+      FutureUtils.get(ReplicationProtobufUtil.replicateWALEntry(
+        connection.getRegionServerAdmin(regionServer.getServerName()), entries, null, null, null,
+        HConstants.REPLICATION_SOURCE_SHIPEDITS_TIMEOUT_DFAULT));
+    } else {
+      try {
+        FutureUtils.get(ReplicationProtobufUtil.replicateWALEntry(
+          connection.getRegionServerAdmin(regionServer.getServerName()), entries, null, null, null,
+          HConstants.REPLICATION_SOURCE_SHIPEDITS_TIMEOUT_DFAULT));
+        fail("Should throw IOException when sync-replication state is in A or DA");
+      } catch (RemoteException e) {
+        assertRejection(e.unwrapRemoteException());
+      } catch (DoNotRetryIOException e) {
+        assertRejection(e);
+      }
+    }
+  }
+
+  protected final void waitUntilDeleted(HBaseTestingUtil util, Path remoteWAL) throws Exception {
+    MasterFileSystem mfs = util.getMiniHBaseCluster().getMaster().getMasterFileSystem();
+    util.waitFor(30000, new ExplainingPredicate<Exception>() {
+
+      @Override
+      public boolean evaluate() throws Exception {
+        return !mfs.getWALFileSystem().exists(remoteWAL);
+      }
+
+      @Override
+      public String explainFailure() throws Exception {
+        return remoteWAL + " has not been deleted yet";
+      }
+    });
   }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBaseNoBeforeAll.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBaseNoBeforeAll.java
deleted file mode 100644
index 13a7ebec346..00000000000
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/SyncReplicationTestBaseNoBeforeAll.java
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- * 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.replication;
-
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.regex.Pattern;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.hbase.DoNotRetryIOException;
-import org.apache.hadoop.hbase.HBaseTestingUtil;
-import org.apache.hadoop.hbase.HBaseZKTestingUtil;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.StartTestingClusterOption;
-import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
-import org.apache.hadoop.hbase.client.Admin;
-import org.apache.hadoop.hbase.client.AsyncClusterConnection;
-import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
-import org.apache.hadoop.hbase.client.Get;
-import org.apache.hadoop.hbase.client.Put;
-import org.apache.hadoop.hbase.client.Table;
-import org.apache.hadoop.hbase.client.TableDescriptor;
-import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
-import org.apache.hadoop.hbase.master.MasterFileSystem;
-import org.apache.hadoop.hbase.protobuf.ReplicationProtobufUtil;
-import org.apache.hadoop.hbase.regionserver.HRegion;
-import org.apache.hadoop.hbase.regionserver.HRegionServer;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.FutureUtils;
-import org.apache.hadoop.hbase.wal.WAL.Entry;
-import org.apache.hadoop.hbase.wal.WALEdit;
-import org.apache.hadoop.hbase.wal.WALKeyImpl;
-import org.apache.hadoop.ipc.RemoteException;
-import org.junit.AfterClass;
-import org.junit.jupiter.api.AfterAll;
-
-import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
-
-/**
- * Sync replication test base without BeforeAll method.
- * @see SyncReplicationTestBase
- */
-public class SyncReplicationTestBaseNoBeforeAll {
-
-  protected static final HBaseZKTestingUtil ZK_UTIL = new HBaseZKTestingUtil();
-
-  protected static final HBaseTestingUtil UTIL1 = new HBaseTestingUtil();
-
-  protected static final HBaseTestingUtil UTIL2 = new HBaseTestingUtil();
-
-  protected static TableName TABLE_NAME = TableName.valueOf("SyncRep");
-
-  protected static byte[] CF = Bytes.toBytes("cf");
-
-  protected static byte[] CQ = Bytes.toBytes("cq");
-
-  protected static String PEER_ID = "1";
-
-  protected static Path REMOTE_WAL_DIR1;
-
-  protected static Path REMOTE_WAL_DIR2;
-
-  protected static void initTestingUtility(HBaseTestingUtil util, String zkParent) {
-    util.setZkCluster(ZK_UTIL.getZkCluster());
-    Configuration conf = util.getConfiguration();
-    conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, zkParent);
-    conf.setInt("replication.source.size.capacity", 102400);
-    conf.setLong("replication.source.sleepforretries", 100);
-    conf.setInt("hbase.regionserver.maxlogs", 10);
-    conf.setLong("hbase.master.logcleaner.ttl", 10);
-    conf.setInt("zookeeper.recovery.retry", 1);
-    conf.setInt("zookeeper.recovery.retry.intervalmill", 10);
-    conf.setLong(HConstants.THREAD_WAKE_FREQUENCY, 100);
-    conf.setInt("replication.stats.thread.period.seconds", 5);
-    conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
-    conf.setLong("replication.sleep.before.failover", 2000);
-    conf.setInt("replication.source.maxretriesmultiplier", 10);
-    conf.setFloat("replication.source.ratio", 1.0f);
-    conf.setBoolean("replication.source.eof.autorecovery", true);
-  }
-
-  protected static void startClusters() throws Exception {
-    ZK_UTIL.startMiniZKCluster();
-    initTestingUtility(UTIL1, "/cluster1");
-    initTestingUtility(UTIL2, "/cluster2");
-    StartTestingClusterOption option =
-      StartTestingClusterOption.builder().numMasters(2).numRegionServers(3).numDataNodes(3).build();
-    UTIL1.startMiniCluster(option);
-    UTIL2.startMiniCluster(option);
-    TableDescriptor td =
-      TableDescriptorBuilder.newBuilder(TABLE_NAME).setColumnFamily(ColumnFamilyDescriptorBuilder
-        .newBuilder(CF).setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build()).build();
-    UTIL1.getAdmin().createTable(td);
-    UTIL2.getAdmin().createTable(td);
-    FileSystem fs1 = UTIL1.getTestFileSystem();
-    FileSystem fs2 = UTIL2.getTestFileSystem();
-    REMOTE_WAL_DIR1 =
-      new Path(UTIL1.getMiniHBaseCluster().getMaster().getMasterFileSystem().getWALRootDir(),
-        "remoteWALs").makeQualified(fs1.getUri(), fs1.getWorkingDirectory());
-    REMOTE_WAL_DIR2 =
-      new Path(UTIL2.getMiniHBaseCluster().getMaster().getMasterFileSystem().getWALRootDir(),
-        "remoteWALs").makeQualified(fs2.getUri(), fs2.getWorkingDirectory());
-    UTIL1.getAdmin().addReplicationPeer(PEER_ID,
-      ReplicationPeerConfig.newBuilder().setClusterKey(UTIL2.getRpcConnnectionURI())
-        .setReplicateAllUserTables(false)
-        .setTableCFsMap(ImmutableMap.of(TABLE_NAME, new ArrayList<>()))
-        .setRemoteWALDir(REMOTE_WAL_DIR2.toUri().toString()).build());
-    UTIL2.getAdmin().addReplicationPeer(PEER_ID,
-      ReplicationPeerConfig.newBuilder().setClusterKey(UTIL1.getRpcConnnectionURI())
-        .setReplicateAllUserTables(false)
-        .setTableCFsMap(ImmutableMap.of(TABLE_NAME, new ArrayList<>()))
-        .setRemoteWALDir(REMOTE_WAL_DIR1.toUri().toString()).build());
-  }
-
-  private static void shutdown(HBaseTestingUtil util) throws Exception {
-    if (util.getHBaseCluster() == null) {
-      return;
-    }
-    Admin admin = util.getAdmin();
-    if (!admin.listReplicationPeers(Pattern.compile(PEER_ID)).isEmpty()) {
-      if (
-        admin.getReplicationPeerSyncReplicationState(PEER_ID)
-            != SyncReplicationState.DOWNGRADE_ACTIVE
-      ) {
-        admin.transitReplicationPeerSyncReplicationState(PEER_ID,
-          SyncReplicationState.DOWNGRADE_ACTIVE);
-      }
-      admin.removeReplicationPeer(PEER_ID);
-    }
-    util.shutdownMiniCluster();
-  }
-
-  @AfterAll
-  @AfterClass
-  public static void tearDown() throws Exception {
-    shutdown(UTIL1);
-    shutdown(UTIL2);
-    ZK_UTIL.shutdownMiniZKCluster();
-  }
-
-  protected final void write(HBaseTestingUtil util, int start, int end) throws IOException {
-    try (Table table = util.getConnection().getTable(TABLE_NAME)) {
-      for (int i = start; i < end; i++) {
-        table.put(new Put(Bytes.toBytes(i)).addColumn(CF, CQ, Bytes.toBytes(i)));
-      }
-    }
-  }
-
-  protected final void verify(HBaseTestingUtil util, int start, int end) throws IOException {
-    try (Table table = util.getConnection().getTable(TABLE_NAME)) {
-      for (int i = start; i < end; i++) {
-        assertEquals(i, Bytes.toInt(table.get(new Get(Bytes.toBytes(i))).getValue(CF, CQ)));
-      }
-    }
-  }
-
-  protected final void verifyThroughRegion(HBaseTestingUtil util, int start, int end)
-    throws IOException {
-    HRegion region = util.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
-    for (int i = start; i < end; i++) {
-      assertEquals(i, Bytes.toInt(region.get(new Get(Bytes.toBytes(i))).getValue(CF, CQ)));
-    }
-  }
-
-  protected final void verifyNotReplicatedThroughRegion(HBaseTestingUtil util, int start, int end)
-    throws IOException {
-    HRegion region = util.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
-    for (int i = start; i < end; i++) {
-      assertTrue(region.get(new Get(Bytes.toBytes(i))).isEmpty());
-    }
-  }
-
-  protected final void waitUntilReplicationDone(HBaseTestingUtil util, int end) throws Exception {
-    // The reject check is in RSRpcService so we can still read through HRegion
-    HRegion region = util.getMiniHBaseCluster().getRegions(TABLE_NAME).get(0);
-    util.waitFor(30000, new ExplainingPredicate<Exception>() {
-
-      @Override
-      public boolean evaluate() throws Exception {
-        return !region.get(new Get(Bytes.toBytes(end - 1))).isEmpty();
-      }
-
-      @Override
-      public String explainFailure() throws Exception {
-        return "Replication has not been catched up yet";
-      }
-    });
-  }
-
-  protected final void writeAndVerifyReplication(HBaseTestingUtil util1, HBaseTestingUtil util2,
-    int start, int end) throws Exception {
-    write(util1, start, end);
-    waitUntilReplicationDone(util2, end);
-    verifyThroughRegion(util2, start, end);
-  }
-
-  protected final Path getRemoteWALDir(MasterFileSystem mfs, String peerId) {
-    Path remoteWALDir = new Path(mfs.getWALRootDir(), ReplicationUtils.REMOTE_WAL_DIR_NAME);
-    return getRemoteWALDir(remoteWALDir, peerId);
-  }
-
-  protected final Path getRemoteWALDir(Path remoteWALDir, String peerId) {
-    return new Path(remoteWALDir, peerId);
-  }
-
-  protected final Path getReplayRemoteWALs(Path remoteWALDir, String peerId) {
-    return new Path(remoteWALDir, peerId + "-replay");
-  }
-
-  protected final void verifyRemovedPeer(String peerId, Path remoteWALDir, HBaseTestingUtil utility)
-    throws Exception {
-    ReplicationPeerStorage rps = ReplicationStorageFactory.getReplicationPeerStorage(
-      utility.getTestFileSystem(), utility.getZooKeeperWatcher(), utility.getConfiguration());
-    try {
-      rps.getPeerSyncReplicationState(peerId);
-      fail("Should throw exception when get the sync replication state of a removed peer.");
-    } catch (ReplicationException e) {
-      // ignore.
-    }
-    try {
-      rps.getPeerNewSyncReplicationState(peerId);
-      fail("Should throw exception when get the new sync replication state of a removed peer");
-    } catch (ReplicationException e) {
-      // ignore.
-    }
-    try (FileSystem fs = utility.getTestFileSystem()) {
-      assertFalse(fs.exists(getRemoteWALDir(remoteWALDir, peerId)));
-      assertFalse(fs.exists(getReplayRemoteWALs(remoteWALDir, peerId)));
-    }
-  }
-
-  private void assertRejection(Throwable error) {
-    assertThat(error, instanceOf(DoNotRetryIOException.class));
-    assertTrue(error.getMessage().contains("Reject to apply to sink cluster"));
-    assertTrue(error.getMessage().contains(TABLE_NAME.toString()));
-  }
-
-  protected final void verifyReplicationRequestRejection(HBaseTestingUtil utility,
-    boolean expectedRejection) throws Exception {
-    HRegionServer regionServer = utility.getRSForFirstRegionInTable(TABLE_NAME);
-    AsyncClusterConnection connection = regionServer.getAsyncClusterConnection();
-    Entry[] entries = new Entry[10];
-    for (int i = 0; i < entries.length; i++) {
-      entries[i] =
-        new Entry(new WALKeyImpl(HConstants.EMPTY_BYTE_ARRAY, TABLE_NAME, 0), new WALEdit());
-    }
-    if (!expectedRejection) {
-      FutureUtils.get(ReplicationProtobufUtil.replicateWALEntry(
-        connection.getRegionServerAdmin(regionServer.getServerName()), entries, null, null, null,
-        HConstants.REPLICATION_SOURCE_SHIPEDITS_TIMEOUT_DFAULT));
-    } else {
-      try {
-        FutureUtils.get(ReplicationProtobufUtil.replicateWALEntry(
-          connection.getRegionServerAdmin(regionServer.getServerName()), entries, null, null, null,
-          HConstants.REPLICATION_SOURCE_SHIPEDITS_TIMEOUT_DFAULT));
-        fail("Should throw IOException when sync-replication state is in A or DA");
-      } catch (RemoteException e) {
-        assertRejection(e.unwrapRemoteException());
-      } catch (DoNotRetryIOException e) {
-        assertRejection(e);
-      }
-    }
-  }
-
-  protected final void waitUntilDeleted(HBaseTestingUtil util, Path remoteWAL) throws Exception {
-    MasterFileSystem mfs = util.getMiniHBaseCluster().getMaster().getMasterFileSystem();
-    util.waitFor(30000, new ExplainingPredicate<Exception>() {
-
-      @Override
-      public boolean evaluate() throws Exception {
-        return !mfs.getWALFileSystem().exists(remoteWAL);
-      }
-
-      @Override
-      public String explainFailure() throws Exception {
-        return remoteWAL + " has not been deleted yet";
-      }
-    });
-  }
-}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBase.java
index 02924dcaa61..5ab593b00ac 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBase.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBase.java
@@ -17,15 +17,264 @@
  */
 package org.apache.hadoop.hbase.replication;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FileSystem;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.HBaseTestingUtil;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.Admin;
+import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
+import org.apache.hadoop.hbase.client.Connection;
+import org.apache.hadoop.hbase.client.ConnectionFactory;
+import org.apache.hadoop.hbase.client.Delete;
+import org.apache.hadoop.hbase.client.Get;
+import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
+import org.apache.hadoop.hbase.client.ResultScanner;
+import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.client.Table;
+import org.apache.hadoop.hbase.client.TableDescriptor;
+import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
+import org.apache.hadoop.hbase.replication.regionserver.HBaseInterClusterReplicationEndpoint;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.hbase.util.JVMClusterUtil;
+import org.apache.hadoop.hbase.wal.WAL;
+import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableList;
+import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
+import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
+import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
 
 /**
  * This class is only a base for other integration-level replication tests. Do not add tests here.
  * TestReplicationSmallTests is where tests that don't require bring machines up/down should go All
  * other tests should have their own classes and extend this one
  */
-public class TestReplicationBase extends TestReplicationBaseNoBeforeAll {
+public class TestReplicationBase {
+  private static final Logger LOG = LoggerFactory.getLogger(TestReplicationBase.class);
+  protected static Connection connection1;
+  protected static Connection connection2;
+  protected static Configuration CONF_WITH_LOCALFS;
+
+  protected static Admin hbaseAdmin;
+
+  protected static Table htable1;
+  protected static Table htable2;
+
+  protected static final HBaseTestingUtil UTIL1 = new HBaseTestingUtil();
+  protected static final HBaseTestingUtil UTIL2 = new HBaseTestingUtil();
+  protected static Configuration CONF1 = UTIL1.getConfiguration();
+  protected static Configuration CONF2 = UTIL2.getConfiguration();
+
+  protected static int NUM_SLAVES1 = 1;
+  protected static int NUM_SLAVES2 = 1;
+  protected static final int NB_ROWS_IN_BATCH = 100;
+  protected static final int NB_ROWS_IN_BIG_BATCH = NB_ROWS_IN_BATCH * 10;
+  protected static final long SLEEP_TIME = 500;
+  protected static final int NB_RETRIES = 50;
+  protected static AtomicInteger replicateCount = new AtomicInteger();
+  protected static volatile List<WAL.Entry> replicatedEntries = Lists.newArrayList();
+
+  protected static final TableName tableName = TableName.valueOf("test");
+  protected static final byte[] famName = Bytes.toBytes("f");
+  protected static final byte[] row = Bytes.toBytes("row");
+  protected static final byte[] noRepfamName = Bytes.toBytes("norep");
+  protected static final String PEER_ID2 = "2";
+
+  protected boolean isSerialPeer() {
+    return false;
+  }
+
+  protected boolean isSyncPeer() {
+    return false;
+  }
+
+  protected final void cleanUp() throws IOException, InterruptedException {
+    // Starting and stopping replication can make us miss new logs,
+    // rolling like this makes sure the most recent one gets added to the queue
+    for (JVMClusterUtil.RegionServerThread r : UTIL1.getHBaseCluster().getRegionServerThreads()) {
+      UTIL1.getAdmin().rollWALWriter(r.getRegionServer().getServerName());
+    }
+    int rowCount = UTIL1.countRows(tableName);
+    UTIL1.deleteTableData(tableName);
+    // truncating the table will send one Delete per row to the slave cluster
+    // in an async fashion, which is why we cannot just call deleteTableData on
+    // utility2 since late writes could make it to the slave in some way.
+    // Instead, we truncate the first table and wait for all the Deletes to
+    // make it to the slave.
+    Scan scan = new Scan();
+    int lastCount = 0;
+    for (int i = 0; i < NB_RETRIES; i++) {
+      if (i == NB_RETRIES - 1) {
+        fail("Waited too much time for truncate");
+      }
+      ResultScanner scanner = htable2.getScanner(scan);
+      Result[] res = scanner.next(rowCount);
+      scanner.close();
+      if (res.length != 0) {
+        if (res.length < lastCount) {
+          i--; // Don't increment timeout if we make progress
+        }
+        lastCount = res.length;
+        LOG.info("Still got " + res.length + " rows");
+        Thread.sleep(SLEEP_TIME);
+      } else {
+        break;
+      }
+    }
+  }
+
+  protected static void waitForReplication(int expectedRows, int retries)
+    throws IOException, InterruptedException {
+    waitForReplication(htable2, expectedRows, retries);
+  }
+
+  protected static void waitForReplication(Table table, int expectedRows, int retries)
+    throws IOException, InterruptedException {
+    Scan scan;
+    for (int i = 0; i < retries; i++) {
+      scan = new Scan();
+      if (i == retries - 1) {
+        fail("Waited too much time for normal batch replication");
+      }
+      int count = 0;
+      try (ResultScanner scanner = table.getScanner(scan)) {
+        while (scanner.next() != null) {
+          count++;
+        }
+      }
+      if (count != expectedRows) {
+        LOG.info("Only got " + count + " rows");
+        Thread.sleep(SLEEP_TIME);
+      } else {
+        break;
+      }
+    }
+  }
+
+  protected static void loadData(String prefix, byte[] row) throws IOException {
+    loadData(prefix, row, famName);
+  }
+
+  protected static void loadData(String prefix, byte[] row, byte[] familyName) throws IOException {
+    List<Put> puts = new ArrayList<>(NB_ROWS_IN_BATCH);
+    for (int i = 0; i < NB_ROWS_IN_BATCH; i++) {
+      Put put = new Put(Bytes.toBytes(prefix + Integer.toString(i)));
+      put.addColumn(familyName, row, row);
+      puts.add(put);
+    }
+    htable1.put(puts);
+  }
+
+  protected static void setupConfig(HBaseTestingUtil util, String znodeParent) {
+    Configuration conf = util.getConfiguration();
+    conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, znodeParent);
+    // We don't want too many edits per batch sent to the ReplicationEndpoint to trigger
+    // sufficient number of events. But we don't want to go too low because
+    // HBaseInterClusterReplicationEndpoint partitions entries into batches and we want
+    // more than one batch sent to the peer cluster for better testing.
+    conf.setInt("replication.source.size.capacity", 102400);
+    conf.setLong("replication.source.sleepforretries", 100);
+    conf.setInt("hbase.regionserver.maxlogs", 10);
+    conf.setLong("hbase.master.logcleaner.ttl", 10);
+    conf.setInt("zookeeper.recovery.retry", 1);
+    conf.setInt("zookeeper.recovery.retry.intervalmill", 10);
+    conf.setLong(HConstants.THREAD_WAKE_FREQUENCY, 100);
+    conf.setInt("replication.stats.thread.period.seconds", 5);
+    conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
+    conf.setLong("replication.sleep.before.failover", 2000);
+    conf.setInt("replication.source.maxretriesmultiplier", 10);
+    conf.setFloat("replication.source.ratio", 1.0f);
+    conf.setBoolean("replication.source.eof.autorecovery", true);
+    conf.setLong("hbase.serial.replication.waiting.ms", 100);
+  }
+
+  static void configureClusters(HBaseTestingUtil util1, HBaseTestingUtil util2) {
+    setupConfig(util1, "/1");
+    setupConfig(util2, "/2");
+
+    Configuration conf2 = util2.getConfiguration();
+    conf2.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/2");
+    conf2.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6);
+    conf2.setBoolean("hbase.tests.use.shortcircuit.reads", false);
+  }
+
+  protected static void restartSourceCluster(int numSlaves) throws Exception {
+    Closeables.close(hbaseAdmin, true);
+    Closeables.close(htable1, true);
+    UTIL1.shutdownMiniHBaseCluster();
+    UTIL1.restartHBaseCluster(numSlaves);
+    // Invalidate the cached connection state.
+    CONF1 = UTIL1.getConfiguration();
+    hbaseAdmin = UTIL1.getAdmin();
+    Connection connection1 = UTIL1.getConnection();
+    htable1 = connection1.getTable(tableName);
+  }
+
+  static void restartTargetHBaseCluster(int numSlaves) throws Exception {
+    Closeables.close(htable2, true);
+    UTIL2.restartHBaseCluster(numSlaves);
+    // Invalidate the cached connection state
+    CONF2 = UTIL2.getConfiguration();
+    htable2 = UTIL2.getConnection().getTable(tableName);
+  }
+
+  protected static void createTable(TableName tableName) throws IOException {
+    TableDescriptor table = TableDescriptorBuilder.newBuilder(tableName)
+      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(famName).setMaxVersions(100)
+        .setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build())
+      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(noRepfamName)).build();
+    UTIL1.createTable(table, HBaseTestingUtil.KEYS_FOR_HBA_CREATE_TABLE);
+    UTIL2.createTable(table, HBaseTestingUtil.KEYS_FOR_HBA_CREATE_TABLE);
+    UTIL1.waitUntilAllRegionsAssigned(tableName);
+    UTIL2.waitUntilAllRegionsAssigned(tableName);
+  }
+
+  private static void startClusters() throws Exception {
+    UTIL1.startMiniZKCluster();
+    MiniZooKeeperCluster miniZK = UTIL1.getZkCluster();
+    LOG.info("Setup first Zk");
+
+    UTIL2.setZkCluster(miniZK);
+    LOG.info("Setup second Zk");
+
+    CONF_WITH_LOCALFS = HBaseConfiguration.create(CONF1);
+    UTIL1.startMiniCluster(NUM_SLAVES1);
+    // Have a bunch of slave servers, because inter-cluster shipping logic uses number of sinks
+    // as a component in deciding maximum number of parallel batches to send to the peer cluster.
+    UTIL2.startMiniCluster(NUM_SLAVES2);
+
+    connection1 = ConnectionFactory.createConnection(CONF1);
+    connection2 = ConnectionFactory.createConnection(CONF2);
+    hbaseAdmin = connection1.getAdmin();
+
+    createTable(tableName);
+    htable1 = connection1.getTable(tableName);
+    htable2 = connection2.getTable(tableName);
+  }
 
   @BeforeAll
   @BeforeClass
@@ -33,4 +282,167 @@ public class TestReplicationBase extends TestReplicationBaseNoBeforeAll {
     configureClusters(UTIL1, UTIL2);
     startClusters();
   }
+
+  private boolean peerExist(String peerId) throws IOException {
+    return peerExist(peerId, UTIL1);
+  }
+
+  private boolean peerExist(String peerId, HBaseTestingUtil util) throws IOException {
+    return util.getAdmin().listReplicationPeers().stream()
+      .anyMatch(p -> peerId.equals(p.getPeerId()));
+  }
+
+  // can be override in tests, in case you need to use zk based uri, or the old style uri
+  protected String getClusterKey(HBaseTestingUtil util) throws Exception {
+    return util.getRpcConnnectionURI();
+  }
+
+  protected final void addPeer(String peerId, TableName tableName) throws Exception {
+    addPeer(peerId, tableName, UTIL1, UTIL2);
+  }
+
+  protected final void addPeer(String peerId, TableName tableName, HBaseTestingUtil source,
+    HBaseTestingUtil target) throws Exception {
+    if (peerExist(peerId, source)) {
+      return;
+    }
+    ReplicationPeerConfigBuilder builder = ReplicationPeerConfig.newBuilder()
+      .setClusterKey(getClusterKey(target)).setSerial(isSerialPeer())
+      .setReplicationEndpointImpl(ReplicationEndpointTest.class.getName());
+    if (isSyncPeer()) {
+      FileSystem fs2 = target.getTestFileSystem();
+      // The remote wal dir is not important as we do not use it in DA state, here we only need to
+      // confirm that a sync peer in DA state can still replicate data to remote cluster
+      // asynchronously.
+      builder.setReplicateAllUserTables(false)
+        .setTableCFsMap(ImmutableMap.of(tableName, ImmutableList.of()))
+        .setRemoteWALDir(new Path("/RemoteWAL")
+          .makeQualified(fs2.getUri(), fs2.getWorkingDirectory()).toUri().toString());
+    }
+    source.getAdmin().addReplicationPeer(peerId, builder.build());
+  }
+
+  @Before
+  @BeforeEach
+  public void setUpBase() throws Exception {
+    addPeer(PEER_ID2, tableName);
+  }
+
+  protected final void removePeer(String peerId) throws Exception {
+    removePeer(peerId, UTIL1);
+  }
+
+  protected final void removePeer(String peerId, HBaseTestingUtil util) throws Exception {
+    if (peerExist(peerId, util)) {
+      util.getAdmin().removeReplicationPeer(peerId);
+    }
+  }
+
+  @After
+  @AfterEach
+  public void tearDownBase() throws Exception {
+    removePeer(PEER_ID2);
+  }
+
+  protected static void runSimplePutDeleteTest() throws IOException, InterruptedException {
+    Put put = new Put(row);
+    put.addColumn(famName, row, row);
+
+    htable1 = UTIL1.getConnection().getTable(tableName);
+    htable1.put(put);
+
+    Get get = new Get(row);
+    for (int i = 0; i < NB_RETRIES; i++) {
+      if (i == NB_RETRIES - 1) {
+        fail("Waited too much time for put replication");
+      }
+      Result res = htable2.get(get);
+      if (res.isEmpty()) {
+        LOG.info("Row not available");
+        Thread.sleep(SLEEP_TIME);
+      } else {
+        assertArrayEquals(row, res.value());
+        break;
+      }
+    }
+
+    Delete del = new Delete(row);
+    htable1.delete(del);
+
+    get = new Get(row);
+    for (int i = 0; i < NB_RETRIES; i++) {
+      if (i == NB_RETRIES - 1) {
+        fail("Waited too much time for del replication");
+      }
+      Result res = htable2.get(get);
+      if (res.size() >= 1) {
+        LOG.info("Row not deleted");
+        Thread.sleep(SLEEP_TIME);
+      } else {
+        break;
+      }
+    }
+  }
+
+  protected static void runSmallBatchTest() throws IOException, InterruptedException {
+    // normal Batch tests
+    loadData("", row);
+
+    Scan scan = new Scan();
+
+    ResultScanner scanner1 = htable1.getScanner(scan);
+    Result[] res1 = scanner1.next(NB_ROWS_IN_BATCH);
+    scanner1.close();
+    assertEquals(NB_ROWS_IN_BATCH, res1.length);
+
+    waitForReplication(NB_ROWS_IN_BATCH, NB_RETRIES);
+  }
+
+  protected static void stopAllRegionServers(HBaseTestingUtil util) throws IOException {
+    List<ServerName> rses = util.getMiniHBaseCluster().getRegionServerThreads().stream()
+      .map(t -> t.getRegionServer().getServerName()).collect(Collectors.toList());
+    for (ServerName rs : rses) {
+      util.getMiniHBaseCluster().stopRegionServer(rs);
+    }
+  }
+
+  @AfterAll
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    if (htable2 != null) {
+      htable2.close();
+    }
+    if (htable1 != null) {
+      htable1.close();
+    }
+    if (hbaseAdmin != null) {
+      hbaseAdmin.close();
+    }
+
+    if (connection2 != null) {
+      connection2.close();
+    }
+    if (connection1 != null) {
+      connection1.close();
+    }
+    UTIL2.shutdownMiniCluster();
+    UTIL1.shutdownMiniCluster();
+  }
+
+  /**
+   * Custom replication endpoint to keep track of replication status for tests.
+   */
+  public static class ReplicationEndpointTest extends HBaseInterClusterReplicationEndpoint {
+    public ReplicationEndpointTest() {
+      replicateCount.set(0);
+    }
+
+    @Override
+    public boolean replicate(ReplicateContext replicateContext) {
+      replicateCount.incrementAndGet();
+      replicatedEntries.addAll(replicateContext.getEntries());
+
+      return super.replicate(replicateContext);
+    }
+  }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBaseNoBeforeAll.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBaseNoBeforeAll.java
deleted file mode 100644
index 35031e3ede0..00000000000
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/TestReplicationBaseNoBeforeAll.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * 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.replication;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.apache.hadoop.hbase.HBaseConfiguration;
-import org.apache.hadoop.hbase.HBaseTestingUtil;
-import org.apache.hadoop.hbase.HConstants;
-import org.apache.hadoop.hbase.ServerName;
-import org.apache.hadoop.hbase.TableName;
-import org.apache.hadoop.hbase.client.Admin;
-import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
-import org.apache.hadoop.hbase.client.Connection;
-import org.apache.hadoop.hbase.client.ConnectionFactory;
-import org.apache.hadoop.hbase.client.Delete;
-import org.apache.hadoop.hbase.client.Get;
-import org.apache.hadoop.hbase.client.Put;
-import org.apache.hadoop.hbase.client.Result;
-import org.apache.hadoop.hbase.client.ResultScanner;
-import org.apache.hadoop.hbase.client.Scan;
-import org.apache.hadoop.hbase.client.Table;
-import org.apache.hadoop.hbase.client.TableDescriptor;
-import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
-import org.apache.hadoop.hbase.replication.regionserver.HBaseInterClusterReplicationEndpoint;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.JVMClusterUtil;
-import org.apache.hadoop.hbase.wal.WAL;
-import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableList;
-import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
-import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
-import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
-
-/**
- * Replication test base class without BeforeAll method, as in some tests we need to do some changes
- * before starting clusters.
- * @see TestReplicationBase
- */
-public class TestReplicationBaseNoBeforeAll {
-  private static final Logger LOG = LoggerFactory.getLogger(TestReplicationBaseNoBeforeAll.class);
-  protected static Connection connection1;
-  protected static Connection connection2;
-  protected static Configuration CONF_WITH_LOCALFS;
-
-  protected static Admin hbaseAdmin;
-
-  protected static Table htable1;
-  protected static Table htable2;
-
-  protected static final HBaseTestingUtil UTIL1 = new HBaseTestingUtil();
-  protected static final HBaseTestingUtil UTIL2 = new HBaseTestingUtil();
-  protected static Configuration CONF1 = UTIL1.getConfiguration();
-  protected static Configuration CONF2 = UTIL2.getConfiguration();
-
-  protected static int NUM_SLAVES1 = 1;
-  protected static int NUM_SLAVES2 = 1;
-  protected static final int NB_ROWS_IN_BATCH = 100;
-  protected static final int NB_ROWS_IN_BIG_BATCH = NB_ROWS_IN_BATCH * 10;
-  protected static final long SLEEP_TIME = 500;
-  protected static final int NB_RETRIES = 50;
-  protected static AtomicInteger replicateCount = new AtomicInteger();
-  protected static volatile List<WAL.Entry> replicatedEntries = Lists.newArrayList();
-
-  protected static final TableName tableName = TableName.valueOf("test");
-  protected static final byte[] famName = Bytes.toBytes("f");
-  protected static final byte[] row = Bytes.toBytes("row");
-  protected static final byte[] noRepfamName = Bytes.toBytes("norep");
-  protected static final String PEER_ID2 = "2";
-
-  protected boolean isSerialPeer() {
-    return false;
-  }
-
-  protected boolean isSyncPeer() {
-    return false;
-  }
-
-  protected final void cleanUp() throws IOException, InterruptedException {
-    // Starting and stopping replication can make us miss new logs,
-    // rolling like this makes sure the most recent one gets added to the queue
-    for (JVMClusterUtil.RegionServerThread r : UTIL1.getHBaseCluster().getRegionServerThreads()) {
-      UTIL1.getAdmin().rollWALWriter(r.getRegionServer().getServerName());
-    }
-    int rowCount = UTIL1.countRows(tableName);
-    UTIL1.deleteTableData(tableName);
-    // truncating the table will send one Delete per row to the slave cluster
-    // in an async fashion, which is why we cannot just call deleteTableData on
-    // utility2 since late writes could make it to the slave in some way.
-    // Instead, we truncate the first table and wait for all the Deletes to
-    // make it to the slave.
-    Scan scan = new Scan();
-    int lastCount = 0;
-    for (int i = 0; i < NB_RETRIES; i++) {
-      if (i == NB_RETRIES - 1) {
-        fail("Waited too much time for truncate");
-      }
-      ResultScanner scanner = htable2.getScanner(scan);
-      Result[] res = scanner.next(rowCount);
-      scanner.close();
-      if (res.length != 0) {
-        if (res.length < lastCount) {
-          i--; // Don't increment timeout if we make progress
-        }
-        lastCount = res.length;
-        LOG.info("Still got " + res.length + " rows");
-        Thread.sleep(SLEEP_TIME);
-      } else {
-        break;
-      }
-    }
-  }
-
-  protected static void waitForReplication(int expectedRows, int retries)
-    throws IOException, InterruptedException {
-    waitForReplication(htable2, expectedRows, retries);
-  }
-
-  protected static void waitForReplication(Table table, int expectedRows, int retries)
-    throws IOException, InterruptedException {
-    Scan scan;
-    for (int i = 0; i < retries; i++) {
-      scan = new Scan();
-      if (i == retries - 1) {
-        fail("Waited too much time for normal batch replication");
-      }
-      int count = 0;
-      try (ResultScanner scanner = table.getScanner(scan)) {
-        while (scanner.next() != null) {
-          count++;
-        }
-      }
-      if (count != expectedRows) {
-        LOG.info("Only got " + count + " rows");
-        Thread.sleep(SLEEP_TIME);
-      } else {
-        break;
-      }
-    }
-  }
-
-  protected static void loadData(String prefix, byte[] row) throws IOException {
-    loadData(prefix, row, famName);
-  }
-
-  protected static void loadData(String prefix, byte[] row, byte[] familyName) throws IOException {
-    List<Put> puts = new ArrayList<>(NB_ROWS_IN_BATCH);
-    for (int i = 0; i < NB_ROWS_IN_BATCH; i++) {
-      Put put = new Put(Bytes.toBytes(prefix + Integer.toString(i)));
-      put.addColumn(familyName, row, row);
-      puts.add(put);
-    }
-    htable1.put(puts);
-  }
-
-  protected static void setupConfig(HBaseTestingUtil util, String znodeParent) {
-    Configuration conf = util.getConfiguration();
-    conf.set(HConstants.ZOOKEEPER_ZNODE_PARENT, znodeParent);
-    // We don't want too many edits per batch sent to the ReplicationEndpoint to trigger
-    // sufficient number of events. But we don't want to go too low because
-    // HBaseInterClusterReplicationEndpoint partitions entries into batches and we want
-    // more than one batch sent to the peer cluster for better testing.
-    conf.setInt("replication.source.size.capacity", 102400);
-    conf.setLong("replication.source.sleepforretries", 100);
-    conf.setInt("hbase.regionserver.maxlogs", 10);
-    conf.setLong("hbase.master.logcleaner.ttl", 10);
-    conf.setInt("zookeeper.recovery.retry", 1);
-    conf.setInt("zookeeper.recovery.retry.intervalmill", 10);
-    conf.setLong(HConstants.THREAD_WAKE_FREQUENCY, 100);
-    conf.setInt("replication.stats.thread.period.seconds", 5);
-    conf.setBoolean("hbase.tests.use.shortcircuit.reads", false);
-    conf.setLong("replication.sleep.before.failover", 2000);
-    conf.setInt("replication.source.maxretriesmultiplier", 10);
-    conf.setFloat("replication.source.ratio", 1.0f);
-    conf.setBoolean("replication.source.eof.autorecovery", true);
-    conf.setLong("hbase.serial.replication.waiting.ms", 100);
-  }
-
-  protected static void configureClusters(HBaseTestingUtil util1, HBaseTestingUtil util2) {
-    setupConfig(util1, "/1");
-    setupConfig(util2, "/2");
-
-    Configuration conf2 = util2.getConfiguration();
-    conf2.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/2");
-    conf2.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 6);
-    conf2.setBoolean("hbase.tests.use.shortcircuit.reads", false);
-  }
-
-  protected static void restartSourceCluster(int numSlaves) throws Exception {
-    Closeables.close(hbaseAdmin, true);
-    Closeables.close(htable1, true);
-    Closeables.close(connection1, true);
-    UTIL1.shutdownMiniHBaseCluster();
-    UTIL1.restartHBaseCluster(numSlaves);
-    // Invalidate the cached connection state.
-    CONF1 = UTIL1.getConfiguration();
-    connection1 = ConnectionFactory.createConnection(CONF1);
-    hbaseAdmin = connection1.getAdmin();
-    htable1 = connection1.getTable(tableName);
-  }
-
-  static void restartTargetHBaseCluster(int numSlaves) throws Exception {
-    Closeables.close(htable2, true);
-    Closeables.close(connection2, true);
-    UTIL2.restartHBaseCluster(numSlaves);
-    // Invalidate the cached connection state
-    CONF2 = UTIL2.getConfiguration();
-    connection2 = ConnectionFactory.createConnection(CONF2);
-    htable2 = connection2.getTable(tableName);
-  }
-
-  protected static void createTable(TableName tableName) throws IOException {
-    TableDescriptor table = TableDescriptorBuilder.newBuilder(tableName)
-      .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(famName).setMaxVersions(100)
-        .setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build())
-      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(noRepfamName)).build();
-    UTIL1.createTable(table, HBaseTestingUtil.KEYS_FOR_HBA_CREATE_TABLE);
-    UTIL2.createTable(table, HBaseTestingUtil.KEYS_FOR_HBA_CREATE_TABLE);
-    UTIL1.waitUntilAllRegionsAssigned(tableName);
-    UTIL2.waitUntilAllRegionsAssigned(tableName);
-  }
-
-  protected static void startClusters() throws Exception {
-    UTIL1.startMiniZKCluster();
-    MiniZooKeeperCluster miniZK = UTIL1.getZkCluster();
-    LOG.info("Setup first Zk");
-
-    UTIL2.setZkCluster(miniZK);
-    LOG.info("Setup second Zk");
-
-    CONF_WITH_LOCALFS = HBaseConfiguration.create(CONF1);
-    UTIL1.startMiniCluster(NUM_SLAVES1);
-    // Have a bunch of slave servers, because inter-cluster shipping logic uses number of sinks
-    // as a component in deciding maximum number of parallel batches to send to the peer cluster.
-    UTIL2.startMiniCluster(NUM_SLAVES2);
-
-    connection1 = ConnectionFactory.createConnection(CONF1);
-    connection2 = ConnectionFactory.createConnection(CONF2);
-    hbaseAdmin = connection1.getAdmin();
-
-    createTable(tableName);
-    htable1 = connection1.getTable(tableName);
-    htable2 = connection2.getTable(tableName);
-  }
-
-  private boolean peerExist(String peerId, HBaseTestingUtil util) throws IOException {
-    return util.getAdmin().listReplicationPeers().stream()
-      .anyMatch(p -> peerId.equals(p.getPeerId()));
-  }
-
-  // can be overridden in tests, in case you need to use zk based uri, or the old style uri
-  protected String getClusterKey(HBaseTestingUtil util) throws Exception {
-    return util.getRpcConnnectionURI();
-  }
-
-  protected final void addPeer(String peerId, TableName tableName) throws Exception {
-    addPeer(peerId, tableName, UTIL1, UTIL2);
-  }
-
-  protected final void addPeer(String peerId, TableName tableName, HBaseTestingUtil source,
-    HBaseTestingUtil target) throws Exception {
-    if (peerExist(peerId, source)) {
-      return;
-    }
-    ReplicationPeerConfigBuilder builder = ReplicationPeerConfig.newBuilder()
-      .setClusterKey(getClusterKey(target)).setSerial(isSerialPeer())
-      .setReplicationEndpointImpl(ReplicationEndpointTest.class.getName());
-    if (isSyncPeer()) {
-      FileSystem fs2 = target.getTestFileSystem();
-      // The remote wal dir is not important as we do not use it in DA state, here we only need to
-      // confirm that a sync peer in DA state can still replicate data to remote cluster
-      // asynchronously.
-      builder.setReplicateAllUserTables(false)
-        .setTableCFsMap(ImmutableMap.of(tableName, ImmutableList.of()))
-        .setRemoteWALDir(new Path("/RemoteWAL")
-          .makeQualified(fs2.getUri(), fs2.getWorkingDirectory()).toUri().toString());
-    }
-    source.getAdmin().addReplicationPeer(peerId, builder.build());
-  }
-
-  @Before
-  @BeforeEach
-  public void setUpBase() throws Exception {
-    addPeer(PEER_ID2, tableName);
-  }
-
-  protected final void removePeer(String peerId) throws Exception {
-    removePeer(peerId, UTIL1);
-  }
-
-  protected final void removePeer(String peerId, HBaseTestingUtil util) throws Exception {
-    if (peerExist(peerId, util)) {
-      util.getAdmin().removeReplicationPeer(peerId);
-    }
-  }
-
-  @After
-  @AfterEach
-  public void tearDownBase() throws Exception {
-    removePeer(PEER_ID2);
-  }
-
-  protected static void runSimplePutDeleteTest() throws IOException, InterruptedException {
-    Put put = new Put(row);
-    put.addColumn(famName, row, row);
-
-    htable1 = UTIL1.getConnection().getTable(tableName);
-    htable1.put(put);
-
-    Get get = new Get(row);
-    for (int i = 0; i < NB_RETRIES; i++) {
-      if (i == NB_RETRIES - 1) {
-        fail("Waited too much time for put replication");
-      }
-      Result res = htable2.get(get);
-      if (res.isEmpty()) {
-        LOG.info("Row not available");
-        Thread.sleep(SLEEP_TIME);
-      } else {
-        assertArrayEquals(row, res.value());
-        break;
-      }
-    }
-
-    Delete del = new Delete(row);
-    htable1.delete(del);
-
-    get = new Get(row);
-    for (int i = 0; i < NB_RETRIES; i++) {
-      if (i == NB_RETRIES - 1) {
-        fail("Waited too much time for del replication");
-      }
-      Result res = htable2.get(get);
-      if (res.size() >= 1) {
-        LOG.info("Row not deleted");
-        Thread.sleep(SLEEP_TIME);
-      } else {
-        break;
-      }
-    }
-  }
-
-  protected static void runSmallBatchTest() throws IOException, InterruptedException {
-    // normal Batch tests
-    loadData("", row);
-
-    Scan scan = new Scan();
-
-    ResultScanner scanner1 = htable1.getScanner(scan);
-    Result[] res1 = scanner1.next(NB_ROWS_IN_BATCH);
-    scanner1.close();
-    assertEquals(NB_ROWS_IN_BATCH, res1.length);
-
-    waitForReplication(NB_ROWS_IN_BATCH, NB_RETRIES);
-  }
-
-  protected static void stopAllRegionServers(HBaseTestingUtil util) throws IOException {
-    List<ServerName> rses = util.getMiniHBaseCluster().getRegionServerThreads().stream()
-      .map(t -> t.getRegionServer().getServerName()).collect(Collectors.toList());
-    for (ServerName rs : rses) {
-      util.getMiniHBaseCluster().stopRegionServer(rs);
-    }
-  }
-
-  @AfterAll
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception {
-    if (htable2 != null) {
-      htable2.close();
-    }
-    if (htable1 != null) {
-      htable1.close();
-    }
-    if (hbaseAdmin != null) {
-      hbaseAdmin.close();
-    }
-
-    if (connection2 != null) {
-      connection2.close();
-    }
-    if (connection1 != null) {
-      connection1.close();
-    }
-    UTIL2.shutdownMiniCluster();
-    UTIL1.shutdownMiniCluster();
-  }
-
-  /**
-   * Custom replication endpoint to keep track of replication status for tests.
-   */
-  public static class ReplicationEndpointTest extends HBaseInterClusterReplicationEndpoint {
-    public ReplicationEndpointTest() {
-      replicateCount.set(0);
-    }
-
-    @Override
-    public boolean replicate(ReplicateContext replicateContext) {
-      replicateCount.incrementAndGet();
-      replicatedEntries.addAll(replicateContext.getEntries());
-
-      return super.replicate(replicateContext);
-    }
-  }
-}
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStream.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStream.java
index c72f7abf507..6d73bc2c79a 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStream.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStream.java
@@ -17,15 +17,14 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-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.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -33,6 +32,7 @@ import static org.mockito.Mockito.when;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.NavigableMap;
@@ -72,8 +72,11 @@ import org.apache.hadoop.hbase.wal.WALEditInternalHelper;
 import org.apache.hadoop.hbase.wal.WALFactory;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
 import org.apache.hadoop.hbase.wal.WALProvider;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.TestTemplate;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 import org.mockito.Mockito;
 
 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos;
@@ -81,13 +84,15 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.WALHeader;
 
 public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
 
-  protected boolean isCompressionEnabled;
+  @Parameter
+  public boolean isCompressionEnabled;
 
-  protected TestBasicWALEntryStream(boolean isCompressionEnabled) {
-    this.isCompressionEnabled = isCompressionEnabled;
+  @Parameters(name = "{index}: isCompressionEnabled={0}")
+  public static Iterable<Object[]> data() {
+    return Arrays.asList(new Object[] { false }, new Object[] { true });
   }
 
-  @BeforeEach
+  @Before
   public void setUp() throws Exception {
     CONF.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, isCompressionEnabled);
     initWAL();
@@ -101,7 +106,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
   /**
    * Tests basic reading of log appends
    */
-  @TestTemplate
+  @Test
   public void testAppendsWithRolls() throws Exception {
     appendToLogAndSync();
     long oldPos;
@@ -156,7 +161,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * Tests that if after a stream is opened, more entries come in and then the log is rolled, we
    * don't mistakenly dequeue the current log thinking we're done with it
    */
-  @TestTemplate
+  @Test
   public void testLogRollWhileStreaming() throws Exception {
     appendToLog("1");
     // 2
@@ -193,7 +198,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * Tests that if writes come in while we have a stream open, we shouldn't miss them
    */
 
-  @TestTemplate
+  @Test
   public void testNewEntriesWhileStreaming() throws Exception {
     appendToLog("1");
     try (WALEntryStream entryStream =
@@ -215,7 +220,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     }
   }
 
-  @TestTemplate
+  @Test
   public void testResumeStreamingFromPosition() throws Exception {
     long lastPosition = 0;
     appendToLog("1");
@@ -240,7 +245,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * Tests that if we stop before hitting the end of a stream, we can continue where we left off
    * using the last position
    */
-  @TestTemplate
+  @Test
   public void testPosition() throws Exception {
     long lastPosition = 0;
     appendEntriesToLogAndSync(3);
@@ -259,7 +264,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     }
   }
 
-  @TestTemplate
+  @Test
   public void testEmptyStream() throws Exception {
     try (WALEntryStream entryStream =
       new WALEntryStream(logQueue, fs, CONF, 0, log, new MetricsSource("1"), fakeWalGroupId)) {
@@ -267,7 +272,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     }
   }
 
-  @TestTemplate
+  @Test
   public void testWALKeySerialization() throws Exception {
     Map<String, byte[]> attributes = new HashMap<String, byte[]>();
     attributes.put("foo", Bytes.toBytes("foo-value"));
@@ -275,7 +280,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     WALKeyImpl key =
       new WALKeyImpl(info.getEncodedNameAsBytes(), tableName, EnvironmentEdgeManager.currentTime(),
         new ArrayList<UUID>(), 0L, 0L, mvcc, scopes, attributes);
-    assertEquals(attributes, key.getExtendedAttributes());
+    Assert.assertEquals(attributes, key.getExtendedAttributes());
 
     WALProtos.WALKey.Builder builder = key.getBuilder(WALCellCodec.getNoneCompressor());
     WALProtos.WALKey serializedKey = builder.build();
@@ -284,14 +289,14 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     deserializedKey.readFieldsFromPb(serializedKey, WALCellCodec.getNoneUncompressor());
 
     // equals() only checks region name, sequence id and write time
-    assertEquals(key, deserializedKey);
+    Assert.assertEquals(key, deserializedKey);
     // can't use Map.equals() because byte arrays use reference equality
-    assertEquals(key.getExtendedAttributes().keySet(),
+    Assert.assertEquals(key.getExtendedAttributes().keySet(),
       deserializedKey.getExtendedAttributes().keySet());
     for (Map.Entry<String, byte[]> entry : deserializedKey.getExtendedAttributes().entrySet()) {
-      assertArrayEquals(key.getExtendedAttribute(entry.getKey()), entry.getValue());
+      Assert.assertArrayEquals(key.getExtendedAttribute(entry.getKey()), entry.getValue());
     }
-    assertEquals(key.getReplicationScopes(), deserializedKey.getReplicationScopes());
+    Assert.assertEquals(key.getReplicationScopes(), deserializedKey.getReplicationScopes());
   }
 
   private ReplicationSource mockReplicationSource(boolean recovered, Configuration conf)
@@ -341,7 +346,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     return reader;
   }
 
-  @TestTemplate
+  @Test
   public void testReplicationSourceWALReader() throws Exception {
     appendEntriesToLogAndSync(3);
     // get ending position
@@ -372,7 +377,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     assertEquals("foo", getRow(entryBatch.getWalEntries().get(0)));
   }
 
-  @TestTemplate
+  @Test
   public void testReplicationSourceWALReaderWithFailingFilter() throws Exception {
     appendEntriesToLogAndSync(3);
     // get ending position
@@ -401,7 +406,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     assertEquals(3, entryBatch.getNbRowKeys());
   }
 
-  @TestTemplate
+  @Test
   public void testReplicationSourceWALReaderRecovered() throws Exception {
     appendEntriesToLogAndSync(10);
     Path walPath = getQueue().peek();
@@ -434,7 +439,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
   }
 
   // Testcase for HBASE-20206
-  @TestTemplate
+  @Test
   public void testReplicationSourceWALReaderWrongPosition() throws Exception {
     appendEntriesToLogAndSync(1);
     Path walPath = getQueue().peek();
@@ -461,8 +466,8 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     assertEquals(walPath, entryBatch.getLastWalPath());
 
     long walLength = fs.getFileStatus(walPath).getLen();
-    assertTrue(entryBatch.getLastWalPosition() <= walLength, "Position "
-      + entryBatch.getLastWalPosition() + " is out of range, file length is " + walLength);
+    assertTrue("Position " + entryBatch.getLastWalPosition() + " is out of range, file length is "
+      + walLength, entryBatch.getLastWalPosition() <= walLength);
     assertEquals(1, entryBatch.getNbEntries());
     assertTrue(entryBatch.isEndOfFile());
 
@@ -486,7 +491,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     assertFalse(entryBatch.isEndOfFile());
   }
 
-  @TestTemplate
+  @Test
   public void testReplicationSourceWALReaderDisabled()
     throws IOException, InterruptedException, ExecutionException {
     appendEntriesToLogAndSync(3);
@@ -594,7 +599,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     }
   }
 
-  @TestTemplate
+  @Test
   public void testReadBeyondCommittedLength() throws IOException, InterruptedException {
     appendToLog("1");
     appendToLog("2");
@@ -621,7 +626,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * Test removal of 0 length log from logQueue if the source is a recovered source and size of
    * logQueue is only 1.
    */
-  @TestTemplate
+  @Test
   public void testEOFExceptionForRecoveredQueue() throws Exception {
     // Create a 0 length log.
     Path emptyLog = new Path("emptyLog");
@@ -652,7 +657,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     assertEquals(0, localLogQueue.getQueueSize(fakeWalGroupId));
   }
 
-  @TestTemplate
+  @Test
   public void testEOFExceptionForRecoveredQueueWithMultipleLogs() throws Exception {
     Configuration conf = new Configuration(CONF);
     MetricsSource metrics = mock(MetricsSource.class);
@@ -677,14 +682,14 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     // Create a reader thread.
     ReplicationSourceWALReader reader = new ReplicationSourceWALReader(fs, conf, localLogQueue, 0,
       getDummyFilter(), source, fakeWalGroupId);
-    assertEquals(2, localLogQueue.getQueueSize(fakeWalGroupId),
-      "Initial log queue size is not correct");
+    assertEquals("Initial log queue size is not correct", 2,
+      localLogQueue.getQueueSize(fakeWalGroupId));
     reader.start();
     reader.join();
 
     // remove empty log from logQueue.
     assertEquals(0, localLogQueue.getQueueSize(fakeWalGroupId));
-    assertEquals(0, localLogQueue.getQueueSize(fakeWalGroupId), "Log queue should be empty");
+    assertEquals("Log queue should be empty", 0, localLogQueue.getQueueSize(fakeWalGroupId));
   }
 
   private PriorityBlockingQueue<Path> getQueue() {
@@ -709,7 +714,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
   /***
    * Tests size of log queue is incremented and decremented properly.
    */
-  @TestTemplate
+  @Test
   public void testSizeOfLogQueue() throws Exception {
     // There should be always 1 log which is current wal.
     assertEquals(1, logQueue.getMetrics().getSizeOfLogQueue());
@@ -740,7 +745,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * Tests that wals are closed cleanly and we read the trailer when we remove wal from
    * WALEntryStream.
    */
-  @TestTemplate
+  @Test
   public void testCleanClosedWALs() throws Exception {
     try (WALEntryStream entryStream = new WALEntryStreamWithRetries(logQueue, fs, CONF, 0, log,
       logQueue.getMetrics(), fakeWalGroupId)) {
@@ -757,7 +762,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
   /**
    * Tests that we handle EOFException properly if the wal has moved to oldWALs directory.
    */
-  @TestTemplate
+  @Test
   public void testEOFExceptionInOldWALsDirectory() throws Exception {
     assertEquals(1, logQueue.getQueueSize(fakeWalGroupId));
     AbstractFSWAL<?> abstractWAL = (AbstractFSWAL<?>) log;
@@ -801,7 +806,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * decreased because {@link WALEntryBatch} is not put to
    * {@link ReplicationSourceWALReader#entryBatchQueue}.
    */
-  @TestTemplate
+  @Test
   public void testReplicationSourceWALReaderWithPartialWALEntryFailingFilter() throws Exception {
     appendEntriesToLogAndSync(3);
     // get ending position
@@ -840,7 +845,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
   }
 
   // testcase for HBASE-28748
-  @TestTemplate
+  @Test
   public void testWALEntryStreamEOFRightAfterHeader() throws Exception {
     assertEquals(1, logQueue.getQueueSize(fakeWalGroupId));
     AbstractFSWAL<?> abstractWAL = (AbstractFSWAL<?>) log;
@@ -883,7 +888,7 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
    * WALEntryFilterRetryableException does not cause the new file to be opened at the old file's
    * position.
    */
-  @TestTemplate
+  @Test
   public void testPositionResetOnFileSwitchWithRetryableFilter() throws Exception {
     appendEntriesToLogAndSync(3);
     log.rollWriter();
@@ -918,15 +923,15 @@ public abstract class TestBasicWALEntryStream extends WALEntryStreamTestBase {
     long deadline = System.currentTimeMillis() + 30000;
     while (totalEntries < 6) {
       long remaining = deadline - System.currentTimeMillis();
-      assertTrue(remaining > 0, "Reader appears stuck - likely position corruption. Only got "
-        + totalEntries + " of 6 entries");
+      assertTrue("Reader appears stuck - likely position corruption. Only got " + totalEntries
+        + " of 6 entries", remaining > 0);
       WALEntryBatch batch = reader.poll(1);
       if (batch != null && batch != WALEntryBatch.NO_MORE_DATA) {
         totalEntries += batch.getNbEntries();
       }
     }
     assertEquals(6, totalEntries);
-    assertTrue(threwOnce.get(), "Filter should have thrown at least once");
+    assertTrue("Filter should have thrown at least once", threwOnce.get());
   }
 
   private static class PartialWALEntryFailingWALEntryFilter implements WALEntryFilter {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamAsyncFSWAL.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamAsyncFSWAL.java
index d4ccfeed5dc..2c37e34ae4e 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamAsyncFSWAL.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamAsyncFSWAL.java
@@ -17,31 +17,30 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import java.util.stream.Stream;
-import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
 import org.apache.hadoop.hbase.wal.AsyncFSWALProvider;
 import org.apache.hadoop.hbase.wal.WALFactory;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.params.provider.Arguments;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-@HBaseParameterizedTestTemplate(name = "{index}: isCompressionEnabled={0}")
+/**
+ * TestBasicWALEntryStream with {@link AsyncFSWALProvider} as the WAL provider.
+ */
+@RunWith(Parameterized.class)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestBasicWALEntryStreamAsyncFSWAL extends TestBasicWALEntryStream {
 
-  public TestBasicWALEntryStreamAsyncFSWAL(boolean isCompressionEnabled) {
-    super(isCompressionEnabled);
-  }
-
-  public static Stream<Arguments> parameters() {
-    return Stream.of(Arguments.of(false), Arguments.of(true));
-  }
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestBasicWALEntryStreamAsyncFSWAL.class);
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().setClass(WALFactory.WAL_PROVIDER, AsyncFSWALProvider.class,
       AbstractFSWALProvider.class);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamFSHLog.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamFSHLog.java
index 84928f8fcbd..7ab9d3fc5a8 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamFSHLog.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestBasicWALEntryStreamFSHLog.java
@@ -17,31 +17,30 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import java.util.stream.Stream;
-import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
 import org.apache.hadoop.hbase.wal.FSHLogProvider;
 import org.apache.hadoop.hbase.wal.WALFactory;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.params.provider.Arguments;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-@HBaseParameterizedTestTemplate(name = "{index}: isCompressionEnabled={0}")
+/**
+ * TestBasicWALEntryStream with {@link FSHLogProvider} as the WAL provider.
+ */
+@RunWith(Parameterized.class)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestBasicWALEntryStreamFSHLog extends TestBasicWALEntryStream {
 
-  public TestBasicWALEntryStreamFSHLog(boolean isCompressionEnabled) {
-    super(isCompressionEnabled);
-  }
-
-  public static Stream<Arguments> parameters() {
-    return Stream.of(Arguments.of(false), Arguments.of(true));
-  }
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestBasicWALEntryStreamFSHLog.class);
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().setClass(WALFactory.WAL_PROVIDER, FSHLogProvider.class,
       AbstractFSWALProvider.class);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDrainReplicationQueuesForStandBy.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDrainReplicationQueuesForStandBy.java
index f33a64876e3..0189d475575 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDrainReplicationQueuesForStandBy.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDrainReplicationQueuesForStandBy.java
@@ -17,8 +17,9 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertTrue;
 
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.Waiter.ExplainingPredicate;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Get;
@@ -33,13 +34,17 @@ import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestDrainReplicationQueuesForStandBy extends SyncReplicationTestBase {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestDrainReplicationQueuesForStandBy.class);
+
   @Test
   public void test() throws Exception {
     UTIL2.getAdmin().transitReplicationPeerSyncReplicationState(PEER_ID,
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDumpReplicationQueues.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDumpReplicationQueues.java
index b5c8e37fb62..3e1dc624fe7 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDumpReplicationQueues.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestDumpReplicationQueues.java
@@ -17,7 +17,7 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -28,6 +28,7 @@ import java.util.Set;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.ServerName;
@@ -42,33 +43,37 @@ import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.apache.hadoop.hbase.util.CommonFSUtils;
 import org.apache.hadoop.hbase.util.Pair;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
 
 /**
  * Tests for DumpReplicationQueues tool
  */
-@Tag(ReplicationTests.TAG)
-@Tag(SmallTests.TAG)
+@Category({ ReplicationTests.class, SmallTests.class })
 public class TestDumpReplicationQueues {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestDumpReplicationQueues.class);
+
   private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
   private static Configuration CONF;
   private static FileSystem FS = null;
   private Path root;
   private Path logDir;
+  @Rule
+  public final TestName name = new TestName();
 
-  private String testName;
-
-  @BeforeEach
-  public void setup(TestInfo testInfo) throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
+  @Before
+  public void setup() throws Exception {
     UTIL.startMiniCluster(3);
     CONF = UTIL.getConfiguration();
-    TableName tableName = TableName.valueOf("replication_" + testName);
+    TableName tableName = TableName.valueOf("replication_" + name.getMethodName());
     UTIL.getAdmin()
       .createTable(ReplicationStorageFactory.createReplicationQueueTableDescriptor(tableName));
     CONF.set(ReplicationStorageFactory.REPLICATION_QUEUE_TABLE_NAME, tableName.getNameAsString());
@@ -114,17 +119,14 @@ public class TestDumpReplicationQueues {
     assertTrue(dump.indexOf("Number of WALs in replication queue: 4") > 0);
     // test for 'Returns wal sorted'
     String[] parsedDump = dump.split("Replication position for");
-    assertTrue(parsedDump[1].indexOf("rs1%2C12345%2C123.10: 123") >= 0,
-      "First wal should be rs1%2C12345%2C123.10: 123, but got: " + parsedDump[1]);
-    assertTrue(
-      parsedDump[2].indexOf("rs1%2C12345%2C123.11: 0 (not started or nothing to replicate)") >= 0,
-      "Second wal should be rs1%2C12345%2C123.11: 0, but got: " + parsedDump[2]);
-    assertTrue(
-      parsedDump[3].indexOf("rs1%2C12345%2C123.12: 0 (not started or nothing to replicate)") >= 0,
-      "Third wal should be rs1%2C12345%2C123.12: 0, but got: " + parsedDump[3]);
-    assertTrue(
-      parsedDump[4].indexOf("rs1%2C12345%2C123.15: 0 (not started or nothing to replicate)") >= 0,
-      "Fourth wal should be rs1%2C12345%2C123.15: 0, but got: " + parsedDump[4]);
+    assertTrue("First wal should be rs1%2C12345%2C123.10: 123, but got: " + parsedDump[1],
+      parsedDump[1].indexOf("rs1%2C12345%2C123.10: 123") >= 0);
+    assertTrue("Second wal should be rs1%2C12345%2C123.11: 0, but got: " + parsedDump[2],
+      parsedDump[2].indexOf("rs1%2C12345%2C123.11: 0 (not started or nothing to replicate)") >= 0);
+    assertTrue("Third wal should be rs1%2C12345%2C123.12: 0, but got: " + parsedDump[3],
+      parsedDump[3].indexOf("rs1%2C12345%2C123.12: 0 (not started or nothing to replicate)") >= 0);
+    assertTrue("Fourth wal should be rs1%2C12345%2C123.15: 0, but got: " + parsedDump[4],
+      parsedDump[4].indexOf("rs1%2C12345%2C123.15: 0 (not started or nothing to replicate)") >= 0);
 
     Path file1 = new Path("testHFile1");
     Path file2 = new Path("testHFile2");
@@ -150,7 +152,7 @@ public class TestDumpReplicationQueues {
     UTIL.getAdmin().addReplicationPeer(peerId, builder.build(), true);
   }
 
-  @AfterEach
+  @After
   public void tearDown() throws Exception {
     UTIL.shutdownMiniCluster();
   }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestGlobalReplicationThrottler.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestGlobalReplicationThrottler.java
index 240880e9a06..6b14438c830 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestGlobalReplicationThrottler.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestGlobalReplicationThrottler.java
@@ -17,9 +17,10 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertTrue;
 
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
@@ -42,18 +43,26 @@ import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.Threads;
 import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
 import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.AfterClass;
+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.hbase.thirdparty.com.google.common.collect.Iterables;
 
-@Tag(ReplicationTests.TAG)
-@Tag(LargeTests.TAG)
+@Category({ ReplicationTests.class, LargeTests.class })
 public class TestGlobalReplicationThrottler {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestGlobalReplicationThrottler.class);
+
+  private static final Logger LOG = LoggerFactory.getLogger(TestGlobalReplicationThrottler.class);
   private static final int REPLICATION_SOURCE_QUOTA = 200;
   private static int numOfPeer = 0;
   private static Configuration conf1;
@@ -67,9 +76,10 @@ public class TestGlobalReplicationThrottler {
   private static final byte[] ROW = Bytes.toBytes("r");
   private static final byte[][] ROWS = HTestConst.makeNAscii(ROW, 100);
 
-  private String testName;
+  @Rule
+  public TestName name = new TestName();
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     conf1 = HBaseConfiguration.create();
     conf1.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/1");
@@ -105,7 +115,7 @@ public class TestGlobalReplicationThrottler {
     }
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     utility2.shutdownMiniCluster();
     utility1.shutdownMiniCluster();
@@ -115,9 +125,8 @@ public class TestGlobalReplicationThrottler {
   private volatile boolean testQuotaNonZero = false;
 
   @Test
-  public void testQuota(TestInfo testInfo) throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
-    final TableName tableName = TableName.valueOf(testName);
+  public void testQuota() throws Exception {
+    final TableName tableName = TableName.valueOf(name.getMethodName());
     TableDescriptor tableDescriptor =
       TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder
         .newBuilder(famName).setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build()).build();
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestHBaseInterClusterReplicationEndpointFilterEdits.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestHBaseInterClusterReplicationEndpointFilterEdits.java
index 817232ed0da..7b108f5ca14 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestHBaseInterClusterReplicationEndpointFilterEdits.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestHBaseInterClusterReplicationEndpointFilterEdits.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -27,6 +27,7 @@ import java.util.List;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.ExtendedCell;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.KeyValue.Type;
@@ -42,10 +43,11 @@ import org.apache.hadoop.hbase.wal.WAL.Entry;
 import org.apache.hadoop.hbase.wal.WALEdit;
 import org.apache.hadoop.hbase.wal.WALEditInternalHelper;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
 
@@ -53,10 +55,13 @@ import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
  * Tests {@link HBaseInterClusterReplicationEndpoint#filterNotExistColumnFamilyEdits(List)} and
  * {@link HBaseInterClusterReplicationEndpoint#filterNotExistTableEdits(List)}
  */
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestHBaseInterClusterReplicationEndpointFilterEdits {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestHBaseInterClusterReplicationEndpointFilterEdits.class);
+
   private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
 
   private static HBaseInterClusterReplicationEndpoint endpoint;
@@ -70,7 +75,7 @@ public class TestHBaseInterClusterReplicationEndpointFilterEdits {
   private static final byte[] ROW = Bytes.toBytes("r");
   private static final byte[] VALUE = Bytes.toBytes("v");
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     UTIL.startMiniCluster();
     ReplicationPeer replicationPeer = mock(ReplicationPeer.class);
@@ -86,7 +91,7 @@ public class TestHBaseInterClusterReplicationEndpointFilterEdits {
     UTIL.createTable(TABLE1, FAMILY);
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     UTIL.shutdownMiniCluster();
   }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestMetaRegionReplicaReplication.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestMetaRegionReplicaReplication.java
index d9a1f9fc186..ab7935ddad4 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestMetaRegionReplicaReplication.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestMetaRegionReplicaReplication.java
@@ -18,10 +18,10 @@
 package org.apache.hadoop.hbase.replication.regionserver;
 
 import static org.apache.hadoop.hbase.client.RegionLocator.LOCATOR_META_REPLICAS_MODE;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -32,6 +32,7 @@ import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellScanner;
 import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.ClientMetaTableAccessor;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.MetaTableAccessor;
@@ -51,14 +52,15 @@ import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.regionserver.Region;
 import org.apache.hadoop.hbase.regionserver.RegionScanner;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
-import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.After;
+import org.junit.Before;
+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;
 
@@ -67,21 +69,23 @@ import org.slf4j.LoggerFactory;
  * replication replays the edits to the secondary region in various scenarios.
  * @see TestRegionReplicaReplication
  */
-@Tag(ReplicationTests.TAG)
-@Tag(LargeTests.TAG)
+@Category({ LargeTests.class })
 public class TestMetaRegionReplicaReplication {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestMetaRegionReplicaReplication.class);
   private static final Logger LOG = LoggerFactory.getLogger(TestMetaRegionReplicaReplication.class);
   private static final int NB_SERVERS = 4;
   private final HBaseTestingUtil HTU = new HBaseTestingUtil();
   private int numOfMetaReplica = NB_SERVERS - 1;
   private static byte[] VALUE = Bytes.toBytes("value");
 
-  private String testName;
+  @Rule
+  public TestName name = new TestName();
 
-  @BeforeEach
-  public void before(TestInfo testInfo) throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
+  @Before
+  public void before() throws Exception {
     Configuration conf = HTU.getConfiguration();
     conf.setInt("zookeeper.recovery.retry", 1);
     conf.setInt("zookeeper.recovery.retry.intervalmill", 10);
@@ -100,7 +104,7 @@ public class TestMetaRegionReplicaReplication {
         >= numOfMetaReplica);
   }
 
-  @AfterEach
+  @After
   public void after() throws Exception {
     HTU.shutdownMiniCluster();
   }
@@ -111,14 +115,14 @@ public class TestMetaRegionReplicaReplication {
    */
   @Test
   public void testHBaseMetaReplicates() throws Exception {
-    try (
-      Table table = HTU.createTable(TableName.valueOf(testName + "_0"), HConstants.CATALOG_FAMILY,
-        Arrays.copyOfRange(HBaseTestingUtil.KEYS, 1, HBaseTestingUtil.KEYS.length))) {
+    try (Table table = HTU.createTable(TableName.valueOf(this.name.getMethodName() + "_0"),
+      HConstants.CATALOG_FAMILY,
+      Arrays.copyOfRange(HBaseTestingUtil.KEYS, 1, HBaseTestingUtil.KEYS.length))) {
       verifyReplication(TableName.META_TABLE_NAME, numOfMetaReplica, getMetaCells(table.getName()));
     }
-    try (
-      Table table = HTU.createTable(TableName.valueOf(testName + "_1"), HConstants.CATALOG_FAMILY,
-        Arrays.copyOfRange(HBaseTestingUtil.KEYS, 1, HBaseTestingUtil.KEYS.length))) {
+    try (Table table = HTU.createTable(TableName.valueOf(this.name.getMethodName() + "_1"),
+      HConstants.CATALOG_FAMILY,
+      Arrays.copyOfRange(HBaseTestingUtil.KEYS, 1, HBaseTestingUtil.KEYS.length))) {
       verifyReplication(TableName.META_TABLE_NAME, numOfMetaReplica, getMetaCells(table.getName()));
       // Try delete.
       HTU.deleteTableIfAny(table.getName());
@@ -372,6 +376,14 @@ public class TestMetaRegionReplicaReplication {
     }
   }
 
+  private void primaryNoChangeReplicaIncrease(final long[] before, final long[] after) {
+    assertEquals(before[RegionInfo.DEFAULT_REPLICA_ID], after[RegionInfo.DEFAULT_REPLICA_ID]);
+
+    for (int i = 1; i < after.length; i++) {
+      assertTrue(after[i] > before[i]);
+    }
+  }
+
   private void primaryIncreaseReplicaNoChange(final long[] before, final long[] after) {
     // There are read requests increase for primary meta replica.
     assertTrue(after[RegionInfo.DEFAULT_REPLICA_ID] > before[RegionInfo.DEFAULT_REPLICA_ID]);
@@ -400,7 +412,7 @@ public class TestMetaRegionReplicaReplication {
 
   @Test
   public void testHBaseMetaReplicaGets() throws Exception {
-    TableName tn = TableName.valueOf(testName);
+    TableName tn = TableName.valueOf(this.name.getMethodName());
     final Region[] metaRegions = getAllRegions(TableName.META_TABLE_NAME, numOfMetaReplica);
     long[] readReqsForMetaReplicas = new long[numOfMetaReplica];
     long[] readReqsForMetaReplicasAfterGet = new long[numOfMetaReplica];
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRaceWhenCreatingReplicationSource.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRaceWhenCreatingReplicationSource.java
index 8ee341ca843..66f04dca36d 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRaceWhenCreatingReplicationSource.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRaceWhenCreatingReplicationSource.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -27,6 +27,7 @@ import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -45,18 +46,22 @@ import org.apache.hadoop.hbase.wal.WAL.Entry;
 import org.apache.hadoop.hbase.wal.WALFactory;
 import org.apache.hadoop.hbase.wal.WALProvider;
 import org.apache.hadoop.hbase.wal.WALStreamReader;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 /**
  * Testcase for HBASE-20624.
  */
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestRaceWhenCreatingReplicationSource {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestRaceWhenCreatingReplicationSource.class);
+
   private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
 
   private static String PEER_ID = "1";
@@ -77,7 +82,7 @@ public class TestRaceWhenCreatingReplicationSource {
 
   public static final class LocalReplicationEndpoint extends BaseReplicationEndpoint {
 
-    private static final UUID PEER_UUID = HBaseTestingUtil.getRandomUUID();
+    private static final UUID PEER_UUID = UTIL.getRandomUUID();
 
     @Override
     public UUID getPeerUUID() {
@@ -129,7 +134,7 @@ public class TestRaceWhenCreatingReplicationSource {
     }
   }
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     UTIL.getConfiguration().set(WALFactory.WAL_PROVIDER, "multiwal");
     // make sure that we will create a new group for the table
@@ -145,7 +150,7 @@ public class TestRaceWhenCreatingReplicationSource {
       true);
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     UTIL.shutdownMiniCluster();
   }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshPeerWhileRegionServerRestarts.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshPeerWhileRegionServerRestarts.java
index ac0d048bf15..e9d8e05c881 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshPeerWhileRegionServerRestarts.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshPeerWhileRegionServerRestarts.java
@@ -17,13 +17,14 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.Future;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.master.replication.DisablePeerProcedure;
 import org.apache.hadoop.hbase.procedure2.Procedure;
@@ -33,8 +34,9 @@ import org.apache.hadoop.hbase.replication.ReplicationPeer.PeerState;
 import org.apache.hadoop.hbase.replication.TestReplicationBase;
 import org.apache.hadoop.hbase.testclassification.MasterTests;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.PeerModificationState;
 
@@ -42,10 +44,13 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.P
  * This UT is used to make sure that we will not accidentally change the way to generate online
  * servers. See HBASE-25774 and HBASE-25032 for more details.
  */
-@Tag(MasterTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ MasterTests.class, MediumTests.class })
 public class TestRefreshPeerWhileRegionServerRestarts extends TestReplicationBase {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestRefreshPeerWhileRegionServerRestarts.class);
+
   private static CountDownLatch ARRIVE;
 
   private static CountDownLatch RESUME;
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshRecoveredReplication.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshRecoveredReplication.java
index 775ff9ef7ce..93aa7130926 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshRecoveredReplication.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRefreshRecoveredReplication.java
@@ -17,33 +17,39 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
 import java.util.List;
 import java.util.Optional;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
 import org.apache.hadoop.hbase.client.Put;
+import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.client.ResultScanner;
 import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.client.Table;
 import org.apache.hadoop.hbase.client.TableDescriptor;
 import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
-import org.apache.hadoop.hbase.replication.TestReplicationBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.TestReplicationBase;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+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;
 
@@ -52,36 +58,44 @@ import org.apache.hbase.thirdparty.org.apache.commons.collections4.CollectionUti
 /**
  * Testcase for HBASE-24871.
  */
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-public class TestRefreshRecoveredReplication extends TestReplicationBaseNoBeforeAll {
+@Category({ ReplicationTests.class, MediumTests.class })
+public class TestRefreshRecoveredReplication extends TestReplicationBase {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestRefreshRecoveredReplication.class);
 
   private static final Logger LOG = LoggerFactory.getLogger(TestRefreshRecoveredReplication.class);
 
   private static final int BATCH = 50;
 
-  @BeforeAll
+  @Rule
+  public TestName name = new TestName();
+
+  private TableName tablename;
+  private Table table1;
+  private Table table2;
+
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     // NUM_SLAVES1 is presumed 2 in below.
     NUM_SLAVES1 = 2;
-    configureClusters(UTIL1, UTIL2);
     // replicate slowly
-    CONF1.setInt(HConstants.REPLICATION_SOURCE_TOTAL_BUFFER_KEY, 100);
-    startClusters();
+    Configuration conf1 = UTIL1.getConfiguration();
+    conf1.setInt(HConstants.REPLICATION_SOURCE_TOTAL_BUFFER_KEY, 100);
+    TestReplicationBase.setUpBeforeClass();
   }
 
-  private String testName;
-
-  private TableName tablename;
-  private Table table1;
-  private Table table2;
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TestReplicationBase.tearDownAfterClass();
+  }
 
-  @BeforeEach
-  public void setup(TestInfo testInfo) throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
+  @Before
+  public void setup() throws Exception {
     setUpBase();
 
-    tablename = TableName.valueOf(testName);
+    tablename = TableName.valueOf(name.getMethodName());
     TableDescriptor table =
       TableDescriptorBuilder.newBuilder(tablename).setColumnFamily(ColumnFamilyDescriptorBuilder
         .newBuilder(famName).setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build()).build();
@@ -94,7 +108,7 @@ public class TestRefreshRecoveredReplication extends TestReplicationBaseNoBefore
     table2 = UTIL2.getConnection().getTable(tablename);
   }
 
-  @AfterEach
+  @After
   public void teardown() throws Exception {
     tearDownBase();
 
@@ -116,7 +130,7 @@ public class TestRefreshRecoveredReplication extends TestReplicationBaseNoBefore
     Optional<RegionServerThread> server = rss.stream()
       .filter(rst -> CollectionUtils.isNotEmpty(rst.getRegionServer().getRegions(tablename)))
       .findAny();
-    assertTrue(server.isPresent());
+    Assert.assertTrue(server.isPresent());
     HRegionServer otherServer = rss.get(0).getRegionServer() == server.get().getRegionServer()
       ? rss.get(1).getRegionServer()
       : rss.get(0).getRegionServer();
@@ -145,10 +159,9 @@ public class TestRefreshRecoveredReplication extends TestReplicationBaseNoBefore
 
   private int checkReplicationData() throws IOException {
     int count = 0;
-    try (ResultScanner results = table2.getScanner(new Scan().setCaching(BATCH))) {
-      while (results.next() != null) {
-        count++;
-      }
+    ResultScanner results = table2.getScanner(new Scan().setCaching(BATCH));
+    for (Result r : results) {
+      count++;
     }
     return count;
   }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplication.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplication.java
index 33e0a15f788..777232f68e9 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplication.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestRegionReplicaReplication.java
@@ -17,12 +17,13 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.Assert.assertNotNull;
 
 import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -41,11 +42,13 @@ import org.apache.hadoop.hbase.replication.ReplicationException;
 import org.apache.hadoop.hbase.testclassification.FlakeyTests;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.util.ServerRegionReplicaUtil;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.AfterClass;
+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;
 
@@ -55,19 +58,23 @@ import org.apache.hbase.thirdparty.com.google.common.util.concurrent.Uninterrupt
  * Tests region replication by setting up region replicas and verifying async wal replication
  * replays the edits to the secondary region in various scenarios.
  */
-@Tag(FlakeyTests.TAG)
-@Tag(LargeTests.TAG)
+@Category({ FlakeyTests.class, LargeTests.class })
 public class TestRegionReplicaReplication {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestRegionReplicaReplication.class);
+
   private static final Logger LOG = LoggerFactory.getLogger(TestRegionReplicaReplication.class);
 
   private static final int NB_SERVERS = 2;
 
   private static final HBaseTestingUtil HTU = new HBaseTestingUtil();
 
-  private String testName;
+  @Rule
+  public TestName name = new TestName();
 
-  @BeforeAll
+  @BeforeClass
   public static void beforeClass() throws Exception {
     Configuration conf = HTU.getConfiguration();
     conf.setFloat("hbase.regionserver.logroll.multiplier", 0.0003f);
@@ -86,7 +93,7 @@ public class TestRegionReplicaReplication {
     HTU.startMiniCluster(NB_SERVERS);
   }
 
-  @AfterAll
+  @AfterClass
   public static void afterClass() throws Exception {
     HTU.shutdownMiniCluster();
   }
@@ -189,10 +196,9 @@ public class TestRegionReplicaReplication {
   }
 
   @Test
-  public void testRegionReplicaWithoutMemstoreReplication(TestInfo testInfo) throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
+  public void testRegionReplicaWithoutMemstoreReplication() throws Exception {
     int regionReplication = 3;
-    TableDescriptor htd = HTU.createModifyableTableDescriptor(testName)
+    TableDescriptor htd = HTU.createModifyableTableDescriptor(name.getMethodName())
       .setRegionReplication(regionReplication).setRegionMemStoreReplication(false).build();
     createOrEnableTableWithRetries(htd, true);
     final TableName tableName = htd.getTableName();
@@ -220,16 +226,14 @@ public class TestRegionReplicaReplication {
   }
 
   @Test
-  public void testRegionReplicaReplicationForFlushAndCompaction(TestInfo testInfo)
-    throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
+  public void testRegionReplicaReplicationForFlushAndCompaction() throws Exception {
     // Tests a table with region replication 3. Writes some data, and causes flushes and
     // compactions. Verifies that the data is readable from the replicas. Note that this
     // does not test whether the replicas actually pick up flushed files and apply compaction
     // to their stores
     int regionReplication = 3;
-    TableDescriptor htd =
-      HTU.createModifyableTableDescriptor(testName).setRegionReplication(regionReplication).build();
+    TableDescriptor htd = HTU.createModifyableTableDescriptor(name.getMethodName())
+      .setRegionReplication(regionReplication).build();
     createOrEnableTableWithRetries(htd, true);
     final TableName tableName = htd.getTableName();
 
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationCompressedWAL.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationCompressedWAL.java
index c57d252bd8a..27c39cc0df2 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationCompressedWAL.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationCompressedWAL.java
@@ -17,37 +17,46 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.fail;
 
 import java.io.IOException;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.client.Get;
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.client.Result;
-import org.apache.hadoop.hbase.replication.TestReplicationBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.TestReplicationBase;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-public class TestReplicationCompressedWAL extends TestReplicationBaseNoBeforeAll {
+@Category(MediumTests.class)
+public class TestReplicationCompressedWAL extends TestReplicationBase {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationCompressedWAL.class);
 
   static final Logger LOG = LoggerFactory.getLogger(TestReplicationCompressedWAL.class);
   static final int NUM_BATCHES = 20;
   static final int NUM_ROWS_PER_BATCH = 100;
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
-    configureClusters(UTIL1, UTIL2);
     CONF1.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, true);
-    startClusters();
+    TestReplicationBase.setUpBeforeClass();
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TestReplicationBase.tearDownAfterClass();
   }
 
   @Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationMarker.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationMarker.java
index 884dd650a78..1466f5f5a03 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationMarker.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationMarker.java
@@ -25,9 +25,9 @@ import static org.apache.hadoop.hbase.replication.master.ReplicationSinkTrackerT
 import static org.apache.hadoop.hbase.replication.master.ReplicationSinkTrackerTableCreator.WAL_NAME_COLUMN;
 import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_CHORE_DURATION_KEY;
 import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_ENABLED_KEY;
-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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -35,6 +35,7 @@ import java.util.List;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellUtil;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
@@ -52,10 +53,11 @@ import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.wal.WAL;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -67,9 +69,11 @@ import org.slf4j.LoggerFactory;
  * "hbase.regionserver.replication.sink.tracker.enabled" conf key enabled. This will persist the
  * marker rows coming from peer cluster to persist to REPLICATION.SINK_TRACKER table.
  **/
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestReplicationMarker {
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationMarker.class);
 
   private static final Logger LOG = LoggerFactory.getLogger(TestReplicationMarker.class);
 
@@ -78,7 +82,7 @@ public class TestReplicationMarker {
   private static HBaseTestingUtil utility1;
   private static HBaseTestingUtil utility2;
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     conf1 = HBaseConfiguration.create();
     conf1.set(HConstants.ZOOKEEPER_ZNODE_PARENT, "/1");
@@ -107,15 +111,15 @@ public class TestReplicationMarker {
     ReplicationSourceManager manager = utility1.getHBaseCluster().getRegionServer(0)
       .getReplicationSourceService().getReplicationManager();
     // Wait until the peer gets established.
-    Waiter.waitFor(conf1, 10000, () -> manager.getSources().size() == 1);
+    Waiter.waitFor(conf1, 10000, (Waiter.Predicate) () -> manager.getSources().size() == 1);
   }
 
   private static void waitForReplicationTrackerTableCreation() {
-    Waiter.waitFor(conf2, 10000,
-      () -> utility2.getAdmin().tableExists(REPLICATION_SINK_TRACKER_TABLE_NAME));
+    Waiter.waitFor(conf2, 10000, (Waiter.Predicate) () -> utility2.getAdmin()
+      .tableExists(REPLICATION_SINK_TRACKER_TABLE_NAME));
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDown() throws Exception {
     utility1.shutdownMiniCluster();
     utility2.shutdownMiniCluster();
@@ -127,14 +131,14 @@ public class TestReplicationMarker {
     // create enough sentinel rows.
     Thread.sleep(5000);
     WAL wal1 = utility1.getHBaseCluster().getRegionServer(0).getWAL(null);
-    String walName1ForCluster1 = ((AbstractFSWAL<?>) wal1).getCurrentFileName().getName();
+    String walName1ForCluster1 = ((AbstractFSWAL) wal1).getCurrentFileName().getName();
     String rs1Name = utility1.getHBaseCluster().getRegionServer(0).getServerName().getHostname();
     // Since we sync the marker edits while appending to wal, all the edits should be visible
     // to Replication threads immediately.
     assertTrue(getReplicatedEntries() >= 5);
     // Force log roll.
     wal1.rollWriter(true);
-    String walName2ForCluster1 = ((AbstractFSWAL<?>) wal1).getCurrentFileName().getName();
+    String walName2ForCluster1 = ((AbstractFSWAL) wal1).getCurrentFileName().getName();
     Connection connection2 = utility2.getMiniHBaseCluster().getRegionServer(0).getConnection();
     // Sleep for 5 more seconds to get marker rows with new wal name.
     Thread.sleep(5000);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSink.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSink.java
index 256bb0fd311..bdb51ebe36f 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSink.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSink.java
@@ -17,8 +17,7 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.fail;
+import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -37,6 +36,7 @@ import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.FileUtil;
 import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.ExtendedCell;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.KeyValue;
@@ -63,11 +63,13 @@ import org.apache.hadoop.hbase.util.CommonFSUtils;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.util.HFileTestUtil;
 import org.apache.hadoop.hbase.wal.WALEditInternalHelper;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -79,10 +81,13 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.UUID;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.WALKey;
 
-@Tag(ReplicationTests.TAG)
-@Tag(LargeTests.TAG)
+@Category({ ReplicationTests.class, LargeTests.class })
 public class TestReplicationSink {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationSink.class);
+
   private static final Logger LOG = LoggerFactory.getLogger(TestReplicationSink.class);
   private static final int BATCH_SIZE = 10;
 
@@ -118,7 +123,10 @@ public class TestReplicationSink {
   protected static String hfileArchiveDir;
   protected static String replicationClusterId;
 
-  @BeforeAll
+  /**
+   * @throws java.lang.Exception
+   */
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().set("hbase.replication.source.fs.conf.provider",
       TestSourceFSConfigurationProvider.class.getCanonicalName());
@@ -134,13 +142,19 @@ public class TestReplicationSink {
     replicationClusterId = "12345";
   }
 
-  @AfterAll
+  /**
+   * @throws java.lang.Exception
+   */
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     STOPPABLE.stop("Shutting down");
     TEST_UTIL.shutdownMiniCluster();
   }
 
-  @BeforeEach
+  /**
+   * @throws java.lang.Exception
+   */
+  @Before
   public void setUp() throws Exception {
     table1 = TEST_UTIL.deleteTableData(TABLE_NAME1);
     table2 = TEST_UTIL.deleteTableData(TABLE_NAME2);
@@ -306,7 +320,7 @@ public class TestReplicationSink {
     try {
       SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
         replicationClusterId, baseNamespaceDir, hfileArchiveDir);
-      fail("Should re-throw TableNotFoundException.");
+      Assert.fail("Should re-throw TableNotFoundException.");
     } catch (TableNotFoundException e) {
     }
     entries.clear();
@@ -321,7 +335,7 @@ public class TestReplicationSink {
           SINK.replicateEntries(entries,
             PrivateCellUtil.createExtendedCellScanner(cells.iterator()), replicationClusterId,
             baseNamespaceDir, hfileArchiveDir);
-          fail("Should re-throw RetriesExhaustedWithDetailsException.");
+          Assert.fail("Should re-throw RetriesExhaustedWithDetailsException.");
         } catch (RetriesExhaustedException e) {
         } finally {
           admin.enableTable(TABLE_NAME1);
@@ -427,7 +441,7 @@ public class TestReplicationSink {
     try {
       SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
         replicationClusterId, baseNamespaceDir, hfileArchiveDir);
-      fail("Should re-throw ArrayIndexOutOfBoundsException.");
+      Assert.fail("Should re-throw ArrayIndexOutOfBoundsException.");
     } catch (ArrayIndexOutOfBoundsException e) {
       errorCount++;
       assertEquals(initialFailedBatches + errorCount, SINK.getSinkMetrics().getFailedBatches());
@@ -442,7 +456,7 @@ public class TestReplicationSink {
     try {
       SINK.replicateEntries(entries, PrivateCellUtil.createExtendedCellScanner(cells.iterator()),
         replicationClusterId, baseNamespaceDir, hfileArchiveDir);
-      fail("Should re-throw TableNotFoundException.");
+      Assert.fail("Should re-throw TableNotFoundException.");
     } catch (TableNotFoundException e) {
       errorCount++;
       assertEquals(initialFailedBatches + errorCount, SINK.getSinkMetrics().getFailedBatches());
@@ -461,7 +475,7 @@ public class TestReplicationSink {
           SINK.replicateEntries(entries,
             PrivateCellUtil.createExtendedCellScanner(cells.iterator()), replicationClusterId,
             baseNamespaceDir, hfileArchiveDir);
-          fail("Should re-throw IOException.");
+          Assert.fail("Should re-throw IOException.");
         } catch (IOException e) {
           errorCount++;
           assertEquals(initialFailedBatches + errorCount, SINK.getSinkMetrics().getFailedBatches());
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSource.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSource.java
index 468ff3940fc..37af52eb93b 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSource.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSource.java
@@ -18,11 +18,11 @@
 package org.apache.hadoop.hbase.replication.regionserver;
 
 import static org.apache.hadoop.hbase.wal.AbstractFSWALProvider.META_WAL_PROVIDER_ID;
-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.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellBuilderType;
 import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
 import org.apache.hadoop.hbase.ExtendedCellBuilderFactory;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
@@ -70,20 +71,24 @@ import org.apache.hadoop.hbase.wal.WALFactory;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
 import org.apache.hadoop.hbase.wal.WALProvider;
 import org.apache.hadoop.hbase.wal.WALStreamReader;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.mockito.Mockito;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestReplicationSource {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationSource.class);
+
   private static final Logger LOG = LoggerFactory.getLogger(TestReplicationSource.class);
   private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
   private final static HBaseTestingUtil TEST_UTIL_PEER = new HBaseTestingUtil();
@@ -92,7 +97,7 @@ public class TestReplicationSource {
   private static Path logDir;
   private static Configuration conf = TEST_UTIL.getConfiguration();
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.startMiniDFSCluster(1);
     FS = TEST_UTIL.getDFSCluster().getFileSystem();
@@ -107,7 +112,7 @@ public class TestReplicationSource {
     }
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     TEST_UTIL_PEER.shutdownMiniHBaseCluster();
     TEST_UTIL.shutdownMiniHBaseCluster();
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceLogQueue.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceLogQueue.java
index 4608100b42c..9d101b97217 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceLogQueue.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceLogQueue.java
@@ -17,25 +17,30 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.util.ManualEnvironmentEdge;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.mockito.Mockito;
 
-@Tag(SmallTests.TAG)
-@Tag(ReplicationTests.TAG)
+@Category({ SmallTests.class, ReplicationTests.class })
 public class TestReplicationSourceLogQueue {
 
-  /**
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationSourceLogQueue.class);
+
+  /*
    * Testing enqueue and dequeuing of wal and check age of oldest wal.
    */
   @Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManager.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManager.java
index fe954074d7c..aadf5982b68 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManager.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManager.java
@@ -20,9 +20,9 @@ package org.apache.hadoop.hbase.replication.regionserver;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasItems;
 import static org.hamcrest.Matchers.hasSize;
-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.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -40,6 +40,7 @@ import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellBuilderType;
 import org.apache.hadoop.hbase.CompatibilitySingletonFactory;
 import org.apache.hadoop.hbase.ExtendedCellBuilderFactory;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.Server;
@@ -70,20 +71,25 @@ import org.apache.hadoop.hbase.wal.WALEditInternalHelper;
 import org.apache.hadoop.hbase.wal.WALFactory;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
 import org.hamcrest.Matchers;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.After;
+import org.junit.AfterClass;
+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.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestReplicationSourceManager {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationSourceManager.class);
+
   public static final class ReplicationEndpointForTest extends DummyReplicationEndpoint {
 
     private String clusterKey;
@@ -122,7 +128,8 @@ public class TestReplicationSourceManager {
 
   private static NavigableMap<byte[], Integer> SCOPES;
 
-  private String testName;
+  @Rule
+  public final TestName name = new TestName();
 
   private Path oldLogDir;
 
@@ -136,7 +143,7 @@ public class TestReplicationSourceManager {
 
   private ReplicationSourceManager manager;
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     UTIL.startMiniCluster(1);
     FS = UTIL.getTestFileSystem();
@@ -149,15 +156,14 @@ public class TestReplicationSourceManager {
     SCOPES.put(F2, 0);
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws IOException {
     UTIL.shutdownMiniCluster();
   }
 
-  @BeforeEach
-  public void setUp(TestInfo testInfo) throws Exception {
-    testName = testInfo.getTestMethod().get().getName();
-    Path rootDir = UTIL.getDataTestDirOnTestFS(testName);
+  @Before
+  public void setUp() throws Exception {
+    Path rootDir = UTIL.getDataTestDirOnTestFS(name.getMethodName());
     CommonFSUtils.setRootDir(CONF, rootDir);
     server = mock(Server.class);
     when(server.getConfiguration()).thenReturn(CONF);
@@ -171,7 +177,7 @@ public class TestReplicationSourceManager {
     FS.mkdirs(logDir);
     remoteLogDir = new Path(rootDir, ReplicationUtils.REMOTE_WAL_DIR_NAME);
     FS.mkdirs(remoteLogDir);
-    TableName tableName = TableName.valueOf("replication_" + testName);
+    TableName tableName = TableName.valueOf("replication_" + name.getMethodName());
     UTIL.getAdmin()
       .createTable(ReplicationStorageFactory.createReplicationQueueTableDescriptor(tableName));
     CONF.set(ReplicationStorageFactory.REPLICATION_QUEUE_TABLE_NAME, tableName.getNameAsString());
@@ -182,7 +188,7 @@ public class TestReplicationSourceManager {
     manager = replication.getReplicationManager();
   }
 
-  @AfterEach
+  @After
   public void tearDown() {
     replication.stopReplicationService();
   }
@@ -395,21 +401,22 @@ public class TestReplicationSourceManager {
 
     ReplicationSource source = (ReplicationSource) manager.getSources().stream()
       .filter(s -> s.getPeerId().equals(peerId)).findFirst().orElse(null);
-    assertNotNull(source, "Source should be created for peer");
+    assertNotNull("Source should be created for peer", source);
 
-    assertEquals(peerSleepOverride, source.getSleepForRetries(),
-      "ReplicationSource should use peer config override for sleepForRetries");
+    assertEquals("ReplicationSource should use peer config override for sleepForRetries",
+      peerSleepOverride, source.getSleepForRetries());
 
     Map<String, ReplicationSourceShipper> workers = source.workerThreads;
     if (!workers.isEmpty()) {
       ReplicationSourceShipper shipper = workers.values().iterator().next();
-      assertEquals(peerSleepOverride, shipper.getSleepForRetries(),
-        "ReplicationSourceShipper should use peer config override for sleepForRetries");
+      assertEquals("ReplicationSourceShipper should use peer config override for sleepForRetries",
+        peerSleepOverride, shipper.getSleepForRetries());
 
       ReplicationSourceWALReader reader = shipper.entryReader;
       if (reader != null) {
-        assertEquals(peerSleepOverride, reader.getSleepForRetries(),
-          "ReplicationSourceWALReader should use peer config override for sleepForRetries");
+        assertEquals(
+          "ReplicationSourceWALReader should use peer config override for sleepForRetries",
+          peerSleepOverride, reader.getSleepForRetries());
       }
     }
 
@@ -452,16 +459,16 @@ public class TestReplicationSourceManager {
     // Verify peer with override uses the override value
     ReplicationSource sourceWithOverride = (ReplicationSource) manager.getSources().stream()
       .filter(s -> s.getPeerId().equals(peerIdWithOverride)).findFirst().orElse(null);
-    assertNotNull(sourceWithOverride, "Source with override should be created");
-    assertEquals(peerSleepOverride, sourceWithOverride.getSleepForRetries(),
-      "Peer with override should use override value");
+    assertNotNull("Source with override should be created", sourceWithOverride);
+    assertEquals("Peer with override should use override value", peerSleepOverride,
+      sourceWithOverride.getSleepForRetries());
 
     // Verify peer without override uses global config
     ReplicationSource sourceWithoutOverride = (ReplicationSource) manager.getSources().stream()
       .filter(s -> s.getPeerId().equals(peerIdWithoutOverride)).findFirst().orElse(null);
-    assertNotNull(sourceWithoutOverride, "Source without override should be created");
-    assertEquals(globalSleepValue, sourceWithoutOverride.getSleepForRetries(),
-      "Peer without override should use global config");
+    assertNotNull("Source without override should be created", sourceWithoutOverride);
+    assertEquals("Peer without override should use global config", globalSleepValue,
+      sourceWithoutOverride.getSleepForRetries());
 
     removePeerAndWait(peerIdWithOverride);
     removePeerAndWait(peerIdWithoutOverride);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManagerJoin.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManagerJoin.java
index 3362a223fbd..d7d23783eac 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManagerJoin.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationSourceManagerJoin.java
@@ -17,11 +17,12 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import java.util.Optional;
 import java.util.stream.Stream;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
@@ -30,34 +31,40 @@ import org.apache.hadoop.hbase.client.Table;
 import org.apache.hadoop.hbase.client.TableDescriptor;
 import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
-import org.apache.hadoop.hbase.replication.TestReplicationBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.TestReplicationBase;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.JVMClusterUtil;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+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;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-public class TestReplicationSourceManagerJoin extends TestReplicationBaseNoBeforeAll {
+@Category({ ReplicationTests.class, MediumTests.class })
+public class TestReplicationSourceManagerJoin extends TestReplicationBase {
 
-  @BeforeAll
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationSourceManagerJoin.class);
+
+  @Rule
+  public TestName testName = new TestName();
+
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     // NUM_SLAVES1 is presumed 2 in below.
     NUM_SLAVES1 = 2;
-    configureClusters(UTIL1, UTIL2);
-    startClusters();
+    TestReplicationBase.setUpBeforeClass();
   }
 
   @Test
-  public void testReplicationSourcesTerminate(TestInfo testInfo) throws Exception {
-    String testName = testInfo.getTestMethod().get().getName();
+  public void testReplicationSourcesTerminate() throws Exception {
     // Create table in source cluster only, let TableNotFoundException block peer to avoid
     // recovered source end.
-    TableName tableName = TableName.valueOf(testName);
+    TableName tableName = TableName.valueOf(testName.getMethodName());
     TableDescriptor td = TableDescriptorBuilder.newBuilder(tableName)
       .setColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(famName)
         .setScope(HConstants.REPLICATION_SCOPE_GLOBAL).build())
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationThrottler.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationThrottler.java
index 078c3bc2d84..ce0f7a351e8 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationThrottler.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationThrottler.java
@@ -17,20 +17,25 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Tag(ReplicationTests.TAG)
-@Tag(SmallTests.TAG)
+@Category({ ReplicationTests.class, SmallTests.class })
 public class TestReplicationThrottler {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationThrottler.class);
+
   private static final Logger LOG = LoggerFactory.getLogger(TestReplicationThrottler.class);
 
   /**
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationValueCompressedWAL.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationValueCompressedWAL.java
index 436e745d2cd..03b83964dcc 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationValueCompressedWAL.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationValueCompressedWAL.java
@@ -17,29 +17,38 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.regionserver.wal.CompressionContext;
-import org.apache.hadoop.hbase.replication.TestReplicationBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.TestReplicationBase;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.testclassification.ReplicationTests;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-public class TestReplicationValueCompressedWAL extends TestReplicationBaseNoBeforeAll {
+@Category(MediumTests.class)
+public class TestReplicationValueCompressedWAL extends TestReplicationBase {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationValueCompressedWAL.class);
 
   static final Logger LOG = LoggerFactory.getLogger(TestReplicationValueCompressedWAL.class);
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
-    configureClusters(UTIL1, UTIL2);
     CONF1.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, true);
     CONF1.setBoolean(CompressionContext.ENABLE_WAL_VALUE_COMPRESSION, true);
-    startClusters();
+    TestReplicationBase.setUpBeforeClass();
+  }
+
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TestReplicationBase.tearDownAfterClass();
   }
 
   @Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationWALEdits.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationWALEdits.java
index 6d83def2e6d..bc885db0df5 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationWALEdits.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicationWALEdits.java
@@ -17,9 +17,9 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-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.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -29,6 +29,7 @@ import java.util.NavigableMap;
 import java.util.TreeMap;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -39,8 +40,9 @@ import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.wal.WALEdit;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.hbase.thirdparty.com.google.protobuf.UnsafeByteOperations;
 
@@ -48,10 +50,13 @@ import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos;
 import org.apache.hadoop.hbase.shaded.protobuf.generated.WALProtos.BulkLoadDescriptor;
 
-@Tag(ReplicationTests.TAG)
-@Tag(SmallTests.TAG)
+@Category({ ReplicationTests.class, SmallTests.class })
 public class TestReplicationWALEdits {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicationWALEdits.class);
+
   private static final Configuration CONF = HBaseConfiguration.create();
 
   private static final TableName TABLE_NAME = TableName.valueOf("test");
@@ -113,8 +118,8 @@ public class TestReplicationWALEdits {
     ReplicationSourceWALActionListener.scopeWALEdits(logKey, logEdit, CONF);
 
     // 4. Assert that no bulk load entry scopes are added if bulk load hfile replication is disabled
-    assertNull(logKey.getReplicationScopes(),
-      "No bulk load entries scope should be added if bulk load replication is disabled.");
+    assertNull("No bulk load entries scope should be added if bulk load replication is disabled.",
+      logKey.getReplicationScopes());
   }
 
   @Test
@@ -133,10 +138,10 @@ public class TestReplicationWALEdits {
 
     NavigableMap<byte[], Integer> scopes = logKey.getReplicationScopes();
     // Assert family with replication scope global is present in the key scopes
-    assertTrue(scopes.containsKey(F1),
-      "This family scope is set to global, should be part of replication key scopes.");
+    assertTrue("This family scope is set to global, should be part of replication key scopes.",
+      scopes.containsKey(F1));
     // Assert family with replication scope local is not present in the key scopes
-    assertFalse(scopes.containsKey(F2),
-      "This family scope is set to local, should not be part of replication key scopes");
+    assertFalse("This family scope is set to local, should not be part of replication key scopes",
+      scopes.containsKey(F2));
   }
 }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicator.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicator.java
index c6ca1f3cbbc..979db712ef3 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicator.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestReplicator.java
@@ -17,13 +17,14 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.Assert.assertEquals;
 
 import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.Waiter;
@@ -31,32 +32,35 @@ import org.apache.hadoop.hbase.client.Admin;
 import org.apache.hadoop.hbase.client.Put;
 import org.apache.hadoop.hbase.ipc.RpcServer;
 import org.apache.hadoop.hbase.replication.ReplicationPeerConfig;
-import org.apache.hadoop.hbase.replication.TestReplicationBaseNoBeforeAll;
+import org.apache.hadoop.hbase.replication.TestReplicationBase;
 import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.wal.WAL.Entry;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
-public class TestReplicator extends TestReplicationBaseNoBeforeAll {
+@Category(MediumTests.class)
+public class TestReplicator extends TestReplicationBase {
+
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestReplicator.class);
 
   static final Logger LOG = LoggerFactory.getLogger(TestReplicator.class);
   static final int NUM_ROWS = 10;
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
-    configureClusters(UTIL1, UTIL2);
     // Set RPC size limit to 10kb (will be applied to both source and sink clusters)
     CONF1.setInt(RpcServer.MAX_REQUEST_SIZE, 1024 * 10);
-    startClusters();
+    TestReplicationBase.setUpBeforeClass();
   }
 
   @Test
@@ -100,10 +104,9 @@ public class TestReplicator extends TestReplicationBaseNoBeforeAll {
         }
       });
 
-      assertEquals(NUM_ROWS, ReplicationEndpointForTest.getBatchCount(),
-        "We sent an incorrect number of batches");
-      assertEquals(NUM_ROWS, HBaseTestingUtil.countRows(htable2),
-        "We did not replicate enough rows");
+      assertEquals("We sent an incorrect number of batches", NUM_ROWS,
+        ReplicationEndpointForTest.getBatchCount());
+      assertEquals("We did not replicate enough rows", NUM_ROWS, UTIL2.countRows(htable2));
     } finally {
       hbaseAdmin.removeReplicationPeer("testReplicatorBatching");
     }
@@ -151,13 +154,17 @@ public class TestReplicator extends TestReplicationBaseNoBeforeAll {
         }
       });
 
-      assertEquals(NUM_ROWS, HBaseTestingUtil.countRows(htable2),
-        "We did not replicate enough rows");
+      assertEquals("We did not replicate enough rows", NUM_ROWS, UTIL2.countRows(htable2));
     } finally {
       hbaseAdmin.removeReplicationPeer("testReplicatorWithErrors");
     }
   }
 
+  @AfterClass
+  public static void tearDownAfterClass() throws Exception {
+    TestReplicationBase.tearDownAfterClass();
+  }
+
   private void truncateTable(HBaseTestingUtil util, TableName tablename) throws IOException {
     Admin admin = util.getAdmin();
     admin.disableTable(tableName);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationChecker.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationChecker.java
index 60ab0a41ac2..8731adbe4c2 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationChecker.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationChecker.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
@@ -33,6 +33,7 @@ import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.Cell.Type;
 import org.apache.hadoop.hbase.CellBuilderFactory;
 import org.apache.hadoop.hbase.CellBuilderType;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.Server;
@@ -55,21 +56,26 @@ import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.wal.WAL.Entry;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.AfterClass;
+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.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestSerialReplicationChecker {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestSerialReplicationChecker.class);
+
   private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
 
   private static String PEER_ID = "1";
@@ -82,11 +88,12 @@ public class TestSerialReplicationChecker {
 
   private SerialReplicationChecker checker;
 
-  private String testName;
+  @Rule
+  public final TestName name = new TestName();
 
   private TableName tableName;
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     UTIL.startMiniCluster(1);
     TableName repTable = TableName.valueOf("test_serial_rep");
@@ -96,14 +103,13 @@ public class TestSerialReplicationChecker {
       UTIL.getConfiguration(), repTable);
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     UTIL.shutdownMiniCluster();
   }
 
-  @BeforeEach
-  public void setUp(TestInfo testInfo) throws IOException {
-    testName = testInfo.getTestMethod().get().getName();
+  @Before
+  public void setUp() throws IOException {
     ReplicationSource source = mock(ReplicationSource.class);
     when(source.getPeerId()).thenReturn(PEER_ID);
     when(source.getReplicationQueueStorage()).thenReturn(QUEUE_STORAGE);
@@ -121,7 +127,7 @@ public class TestSerialReplicationChecker {
     when(server.getConnection()).thenReturn(conn);
     when(source.getServer()).thenReturn(server);
     checker = new SerialReplicationChecker(UTIL.getConfiguration(), source);
-    tableName = TableName.valueOf(testName);
+    tableName = TableName.valueOf(name.getMethodName());
   }
 
   private Entry createEntry(RegionInfo region, long seqId) {
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationEndpoint.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationEndpoint.java
index b6d287d3ad7..5f99b88e0a4 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationEndpoint.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSerialReplicationEndpoint.java
@@ -17,9 +17,6 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -29,6 +26,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.LinkedBlockingQueue;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -47,24 +45,29 @@ import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
 import org.apache.hadoop.hbase.wal.WAL.Entry;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableList;
 import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap;
 import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
 
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestSerialReplicationEndpoint {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestSerialReplicationEndpoint.class);
+
   private static HBaseTestingUtil UTIL = new HBaseTestingUtil();
   private static Configuration CONF;
   private static Connection CONN;
 
-  @BeforeAll
+  @BeforeClass
   public static void setUp() throws Exception {
     UTIL.startMiniCluster();
     CONF = UTIL.getConfiguration();
@@ -72,7 +75,7 @@ public class TestSerialReplicationEndpoint {
     CONN = UTIL.getConnection();
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDown() throws Exception {
     Closeables.close(CONN, true);
     UTIL.shutdownMiniCluster();
@@ -114,7 +117,7 @@ public class TestSerialReplicationEndpoint {
     Waiter.waitFor(CONF, 60000, () -> TestEndpoint.getEntries().size() >= cellNum);
 
     int index = 0;
-    assertEquals(cellNum, TestEndpoint.getEntries().size());
+    Assert.assertEquals(TestEndpoint.getEntries().size(), cellNum);
     if (!isSerial) {
       Collections.sort(TestEndpoint.getEntries(), (a, b) -> {
         long seqA = a.getKey().getSequenceId();
@@ -123,14 +126,15 @@ public class TestSerialReplicationEndpoint {
       });
     }
     for (Entry entry : TestEndpoint.getEntries()) {
-      assertEquals(tableName, entry.getKey().getTableName());
-      assertEquals(1, entry.getEdit().getCells().size());
+      Assert.assertEquals(entry.getKey().getTableName(), tableName);
+      Assert.assertEquals(entry.getEdit().getCells().size(), 1);
       Cell cell = entry.getEdit().getCells().get(0);
-      assertArrayEquals(Bytes.toBytes(index),
-        Bytes.copy(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
+      Assert.assertArrayEquals(
+        Bytes.copy(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()),
+        Bytes.toBytes(index));
       index++;
     }
-    assertEquals(cellNum, index);
+    Assert.assertEquals(index, cellNum);
   }
 
   @Test
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSyncReplicationShipperQuit.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSyncReplicationShipperQuit.java
index 7eb587e6cd5..5a0578a35d2 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSyncReplicationShipperQuit.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestSyncReplicationShipperQuit.java
@@ -17,9 +17,10 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.client.RegionInfoBuilder;
 import org.apache.hadoop.hbase.regionserver.HRegionServer;
 import org.apache.hadoop.hbase.regionserver.wal.AbstractFSWAL;
@@ -29,16 +30,20 @@ import org.apache.hadoop.hbase.replication.SyncReplicationTestBase;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 /**
  * Testcase for HBASE-20456.
  */
-@Tag(ReplicationTests.TAG)
-@Tag(LargeTests.TAG)
+@Category({ ReplicationTests.class, LargeTests.class })
 public class TestSyncReplicationShipperQuit extends SyncReplicationTestBase {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestSyncReplicationShipperQuit.class);
+
   @Test
   public void testShipperQuitWhenDA() throws Exception {
     // set to serial replication
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntrySinkFilter.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntrySinkFilter.java
index 0cc36a892cd..11a0e98c554 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntrySinkFilter.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntrySinkFilter.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.net.SocketAddress;
@@ -33,6 +33,7 @@ import org.apache.hadoop.hbase.ExtendedCell;
 import org.apache.hadoop.hbase.ExtendedCellBuilder;
 import org.apache.hadoop.hbase.ExtendedCellBuilderFactory;
 import org.apache.hadoop.hbase.ExtendedCellScanner;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseConfiguration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -50,9 +51,11 @@ import org.apache.hadoop.hbase.security.User;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.testclassification.SmallTests;
 import org.apache.hadoop.hbase.util.Bytes;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
+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.apache.hbase.thirdparty.com.google.protobuf.ByteString;
 
@@ -61,10 +64,15 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.AdminProtos;
 /**
  * Simple test of sink-side wal entry filter facility.
  */
-@Tag(ReplicationTests.TAG)
-@Tag(SmallTests.TAG)
+@Category({ ReplicationTests.class, SmallTests.class })
 public class TestWALEntrySinkFilter {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestWALEntrySinkFilter.class);
+
+  @Rule
+  public TestName name = new TestName();
   static final int BOUNDARY = 5;
   static final AtomicInteger UNFILTERED = new AtomicInteger();
   static final AtomicInteger FILTERED = new AtomicInteger();
@@ -76,8 +84,7 @@ public class TestWALEntrySinkFilter {
    * our counting Table.
    */
   @Test
-  public void testWALEntryFilter(TestInfo testInfo) throws IOException {
-    String testName = testInfo.getTestMethod().get().getName();
+  public void testWALEntryFilter() throws IOException {
     Configuration conf = HBaseConfiguration.create();
     // Make it so our filter is instantiated on construction of ReplicationSink.
     conf.setClass(HConstants.CLIENT_CONNECTION_REGISTRY_IMPL_CONF_KEY,
@@ -91,7 +98,8 @@ public class TestWALEntrySinkFilter {
     List<AdminProtos.WALEntry> entries = new ArrayList<>();
     AdminProtos.WALEntry.Builder entryBuilder = AdminProtos.WALEntry.newBuilder();
     // Need a tablename.
-    ByteString tableName = ByteString.copyFromUtf8(TableName.valueOf(testName).toString());
+    ByteString tableName =
+      ByteString.copyFromUtf8(TableName.valueOf(this.name.getMethodName()).toString());
     // Add WALEdit Cells to Cells List. The way edits arrive at the sink is with protos
     // describing the edit with all Cells from all edits aggregated in a single CellScanner.
     final List<ExtendedCell> cells = new ArrayList<>();
@@ -193,7 +201,7 @@ public class TestWALEntrySinkFilter {
           for (Row action : actions) {
             // Row is the index of the loop above where we make WALEntry and Cells.
             int row = Bytes.toInt(action.getRow());
-            assertTrue(row > BOUNDARY, "" + row);
+            assertTrue("" + row, row > BOUNDARY);
             UNFILTERED.incrementAndGet();
             list.add(null);
           }
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamCompressionReset.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamCompressionReset.java
index 9b182a86ae8..aa30027b3c9 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamCompressionReset.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamCompressionReset.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -34,6 +34,7 @@ import org.apache.hadoop.fs.Path;
 import org.apache.hadoop.hbase.Cell;
 import org.apache.hadoop.hbase.CellBuilderType;
 import org.apache.hadoop.hbase.ExtendedCellBuilderFactory;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.HBaseTestingUtil;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.ServerName;
@@ -52,10 +53,11 @@ import org.apache.hadoop.hbase.wal.WAL;
 import org.apache.hadoop.hbase.wal.WALEdit;
 import org.apache.hadoop.hbase.wal.WALEditInternalHelper;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
 
 import org.apache.hbase.thirdparty.com.google.common.io.ByteStreams;
 
@@ -65,10 +67,13 @@ import org.apache.hbase.thirdparty.com.google.common.io.ByteStreams;
  * This is used to confirm that we can work well when hitting EOFException in the middle when
  * reading a WAL entry, when compression is enabled. See HBASE-27621 for more details.
  */
-@Tag(ReplicationTests.TAG)
-@Tag(MediumTests.TAG)
+@Category({ ReplicationTests.class, MediumTests.class })
 public class TestWALEntryStreamCompressionReset {
 
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestWALEntryStreamCompressionReset.class);
+
   private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
 
   private static TableName TABLE_NAME = TableName.valueOf("reset");
@@ -133,7 +138,7 @@ public class TestWALEntryStreamCompressionReset {
     return Pair.newPair(path, offset);
   }
 
-  @BeforeAll
+  @BeforeClass
   public static void setUp() throws Exception {
     Configuration conf = UTIL.getConfiguration();
     FS = UTIL.getTestFileSystem();
@@ -162,7 +167,7 @@ public class TestWALEntryStreamCompressionReset {
     READER = new ReplicationSourceWALReader(FS, conf, LOG_QUEUE, 0, e -> e, SOURCE, GROUP_ID);
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDown() throws Exception {
     READER.setReaderRunning(false);
     READER.join();
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCounts.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCounts.java
index 41497c3f88f..88f4f4539b2 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCounts.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCounts.java
@@ -17,38 +17,53 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.replication.regionserver.WALEntryStream.HasNext;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.TestTemplate;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 /**
  * Try out different combinations of row count and KeyValue count
  */
 public abstract class TestWALEntryStreamDifferentCounts extends WALEntryStreamTestBase {
 
-  protected int nbRows;
-  protected int walEditKVs;
-  protected boolean isCompressionEnabled;
+  @Parameter(0)
+  public int nbRows;
 
-  protected TestWALEntryStreamDifferentCounts(int nbRows, int walEditKVs,
-    boolean isCompressionEnabled) {
-    this.nbRows = nbRows;
-    this.walEditKVs = walEditKVs;
-    this.isCompressionEnabled = isCompressionEnabled;
+  @Parameter(1)
+  public int walEditKVs;
+
+  @Parameter(2)
+  public boolean isCompressionEnabled;
+
+  @Parameters(name = "{index}: nbRows={0}, walEditKVs={1}, isCompressionEnabled={2}")
+  public static Iterable<Object[]> data() {
+    List<Object[]> params = new ArrayList<>();
+    for (int nbRows : new int[] { 1500, 60000 }) {
+      for (int walEditKVs : new int[] { 1, 100 }) {
+        for (boolean isCompressionEnabled : new boolean[] { false, true }) {
+          params.add(new Object[] { nbRows, walEditKVs, isCompressionEnabled });
+        }
+      }
+    }
+    return params;
   }
 
-  @BeforeEach
+  @Before
   public void setUp() throws IOException {
     CONF.setBoolean(HConstants.ENABLE_WAL_COMPRESSION, isCompressionEnabled);
     initWAL();
   }
 
-  @TestTemplate
+  @Test
   public void testDifferentCounts() throws Exception {
     mvcc.advanceTo(1);
 
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsAsyncFSWAL.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsAsyncFSWAL.java
index 13bab98c187..9dcb8a344b6 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsAsyncFSWAL.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsAsyncFSWAL.java
@@ -17,43 +17,27 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
 import org.apache.hadoop.hbase.wal.AsyncFSWALProvider;
 import org.apache.hadoop.hbase.wal.WALFactory;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.params.provider.Arguments;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
-@Tag(ReplicationTests.TAG)
-@Tag(LargeTests.TAG)
-@HBaseParameterizedTestTemplate(
-    name = "{index}: nbRows={0}, walEditKVs={1}, isCompressionEnabled={2}")
+@RunWith(Parameterized.class)
+@Category({ ReplicationTests.class, LargeTests.class })
 public class TestWALEntryStreamDifferentCountsAsyncFSWAL extends TestWALEntryStreamDifferentCounts {
 
-  public TestWALEntryStreamDifferentCountsAsyncFSWAL(int nbRows, int walEditKVs,
-    boolean isCompressionEnabled) {
-    super(nbRows, walEditKVs, isCompressionEnabled);
-  }
-
-  public static Stream<Arguments> parameters() {
-    List<Arguments> params = new ArrayList<>();
-    for (int nbRows : new int[] { 1500, 60000 }) {
-      for (int walEditKVs : new int[] { 1, 100 }) {
-        for (boolean isCompressionEnabled : new boolean[] { false, true }) {
-          params.add(Arguments.of(nbRows, walEditKVs, isCompressionEnabled));
-        }
-      }
-    }
-    return params.stream();
-  }
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestWALEntryStreamDifferentCountsAsyncFSWAL.class);
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().setClass(WALFactory.WAL_PROVIDER, AsyncFSWALProvider.class,
       AbstractFSWALProvider.class);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsFSHLog.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsFSHLog.java
index 8c4f9eb46a4..fb7c3d555d8 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsFSHLog.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/TestWALEntryStreamDifferentCountsFSHLog.java
@@ -17,43 +17,27 @@
  */
 package org.apache.hadoop.hbase.replication.regionserver;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Stream;
-import org.apache.hadoop.hbase.HBaseParameterizedTestTemplate;
+import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.testclassification.LargeTests;
 import org.apache.hadoop.hbase.testclassification.ReplicationTests;
 import org.apache.hadoop.hbase.wal.AbstractFSWALProvider;
 import org.apache.hadoop.hbase.wal.FSHLogProvider;
 import org.apache.hadoop.hbase.wal.WALFactory;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.params.provider.Arguments;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.experimental.categories.Category;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
 
-@Tag(ReplicationTests.TAG)
-@Tag(LargeTests.TAG)
-@HBaseParameterizedTestTemplate(
-    name = "{index}: nbRows={0}, walEditKVs={1}, isCompressionEnabled={2}")
+@RunWith(Parameterized.class)
+@Category({ ReplicationTests.class, LargeTests.class })
 public class TestWALEntryStreamDifferentCountsFSHLog extends TestWALEntryStreamDifferentCounts {
 
-  public TestWALEntryStreamDifferentCountsFSHLog(int nbRows, int walEditKVs,
-    boolean isCompressionEnabled) {
-    super(nbRows, walEditKVs, isCompressionEnabled);
-  }
-
-  public static Stream<Arguments> parameters() {
-    List<Arguments> params = new ArrayList<>();
-    for (int nbRows : new int[] { 1500, 60000 }) {
-      for (int walEditKVs : new int[] { 1, 100 }) {
-        for (boolean isCompressionEnabled : new boolean[] { false, true }) {
-          params.add(Arguments.of(nbRows, walEditKVs, isCompressionEnabled));
-        }
-      }
-    }
-    return params.stream();
-  }
+  @ClassRule
+  public static final HBaseClassTestRule CLASS_RULE =
+    HBaseClassTestRule.forClass(TestWALEntryStreamDifferentCountsFSHLog.class);
 
-  @BeforeAll
+  @BeforeClass
   public static void setUpBeforeClass() throws Exception {
     TEST_UTIL.getConfiguration().setClass(WALFactory.WAL_PROVIDER, FSHLogProvider.class,
       AbstractFSWALProvider.class);
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/WALEntryStreamTestBase.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/WALEntryStreamTestBase.java
index b4b6af30c47..3af5596b005 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/WALEntryStreamTestBase.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/replication/regionserver/WALEntryStreamTestBase.java
@@ -42,10 +42,10 @@ import org.apache.hadoop.hbase.wal.WALFactory;
 import org.apache.hadoop.hbase.wal.WALKeyImpl;
 import org.apache.hadoop.hdfs.DistributedFileSystem;
 import org.apache.hadoop.hdfs.MiniDFSCluster;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.TestInfo;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Rule;
+import org.junit.rules.TestName;
 
 import org.apache.hbase.thirdparty.com.google.common.io.Closeables;
 
@@ -125,13 +125,10 @@ public abstract class WALEntryStreamTestBase {
   protected WAL log;
   protected ReplicationSourceLogQueue logQueue;
   protected PathWatcher pathWatcher;
-  protected String testName;
-  protected final MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl();
 
-  @BeforeEach
-  public void setUp(TestInfo testInfo) {
-    testName = testInfo.getTestMethod().get().getName();
-  }
+  @Rule
+  public TestName tn = new TestName();
+  protected final MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl();
 
   protected static void startCluster() throws Exception {
     CONF = TEST_UTIL.getConfiguration();
@@ -142,7 +139,7 @@ public abstract class WALEntryStreamTestBase {
     fs = cluster.getFileSystem();
   }
 
-  @AfterAll
+  @AfterClass
   public static void tearDownAfterClass() throws Exception {
     TEST_UTIL.shutdownMiniCluster();
   }
@@ -154,12 +151,12 @@ public abstract class WALEntryStreamTestBase {
     metricsSource.clear();
     logQueue = new ReplicationSourceLogQueue(CONF, metricsSource, source);
     pathWatcher = new PathWatcher();
-    final WALFactory wals = new WALFactory(CONF, testName.replaceAll("[\\[:]", "_"));
+    final WALFactory wals = new WALFactory(CONF, tn.getMethodName().replaceAll("[\\[:]", "_"));
     wals.getWALProvider().addWALActionsListener(pathWatcher);
     log = wals.getWAL(info);
   }
 
-  @AfterEach
+  @After
   public void tearDown() throws Exception {
     Closeables.close(log, true);
   }