@Test
  public void testReaderClosedOnBadCodec() throws IOException {
    // Create our own Configuration and WALFactory to avoid breaking other test methods
    Configuration confWithCodec = new Configuration(conf);
    confWithCodec.setClass(WALCellCodec.WAL_CELL_CODEC_CLASS_KEY, BrokenWALCellCodec.class,
      Codec.class);
    WALFactory customFactory = new WALFactory(confWithCodec, this.currentServername.toString());

    // Hack a Proxy over the FileSystem so that we can track the InputStreams opened by
    // the FileSystem and know if close() was called on those InputStreams.
    List<InputStreamProxy> openedReaders = new ArrayList<>();
    FileSystemProxy proxyFs = new FileSystemProxy(fs) {
      @Override
      public FSDataInputStream open(Path p) throws IOException {
        InputStreamProxy is = new InputStreamProxy(super.open(p));
        openedReaders.add(is);
        return is;
      }

      @Override
      public FSDataInputStream open(Path p, int blockSize) throws IOException {
        InputStreamProxy is = new InputStreamProxy(super.open(p, blockSize));
        openedReaders.add(is);
        return is;
      }
    };

    final TableDescriptor htd =
      TableDescriptorBuilder.newBuilder(TableName.valueOf(currentTest.getMethodName()))
        .setColumnFamily(ColumnFamilyDescriptorBuilder.of("column")).build();
    final RegionInfo hri = RegionInfoBuilder.newBuilder(htd.getTableName()).build();

    NavigableMap<byte[], Integer> scopes = new TreeMap<byte[], Integer>(Bytes.BYTES_COMPARATOR);
    for (byte[] fam : htd.getColumnFamilyNames()) {
      scopes.put(fam, 0);
    }
    byte[] row = Bytes.toBytes("row");
    final MultiVersionConcurrencyControl mvcc = new MultiVersionConcurrencyControl(1);
    // Write one column in one edit.
    WALEdit cols = new WALEdit();
    cols.add(new KeyValue(row, Bytes.toBytes("column"), Bytes.toBytes("0"),
      EnvironmentEdgeManager.currentTime(), new byte[] { 0 }));
    final WAL log = customFactory.getWAL(hri);
    final long txid = log.appendData(hri, new WALKeyImpl(hri.getEncodedNameAsBytes(),
      htd.getTableName(), EnvironmentEdgeManager.currentTime(), mvcc, scopes), cols);
    // Sync the edit to the WAL
    log.sync(txid);
    log.startCacheFlush(hri.getEncodedNameAsBytes(), htd.getColumnFamilyNames());
    log.completeCacheFlush(hri.getEncodedNameAsBytes(), HConstants.NO_SEQNUM);
    log.shutdown();

    // Inject our failure, object is constructed via reflection.
    BrokenWALCellCodec.THROW_FAILURE_ON_INIT.set(true);

    // Now open a reader on the log which will throw an exception when
    // we try to instantiate the custom Codec.
    Path filename = AbstractFSWALProvider.getCurrentFileName(log);
    assertThrows("Expected to see an exception when creating WAL reader", IOException.class,
      () -> customFactory.createStreamReader(proxyFs, filename));
    // We should have exactly one reader
    assertEquals(1, openedReaders.size());
    // And that reader should be closed.
    long unclosedReaders =
      openedReaders.stream().filter((r) -> !r.isClosed.get()).collect(Collectors.counting());
    assertEquals("Should not find any open readers", 0, unclosedReaders);
  }
Confirm that we will use different WALs for hbase:meta and hbase:replication
hbase-server/src/test/java/org/apache/hadoop/hbase/wal/TestWALFactory.java