@Test
  public void testMissingReportsRemovesQuota() throws Exception {
    Configuration conf = TEST_UTIL.getConfiguration();
    // Expire the reports after 5 seconds
    conf.setInt(QuotaObserverChore.REGION_REPORT_RETENTION_DURATION_KEY, 5000);
    TEST_UTIL.startMiniCluster(1);
    // Wait till quota table onlined.
    TEST_UTIL.waitFor(10000, new Waiter.Predicate<Exception>() {
      @Override
      public boolean evaluate() throws Exception {
        return TEST_UTIL.getAdmin().tableExists(QuotaTableUtil.QUOTA_TABLE_NAME);
      }
    });

    final String FAM1 = "f1";

    // Create a table
    final TableName tn = TableName.valueOf("quotaAcceptanceWithoutReports");
    TableDescriptor tableDesc = TableDescriptorBuilder.newBuilder(tn)
      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(FAM1)).build();
    TEST_UTIL.getAdmin().createTable(tableDesc);

    // Set a quota
    final long sizeLimit = 1L * SpaceQuotaHelperForTests.ONE_KILOBYTE;
    final SpaceViolationPolicy violationPolicy = SpaceViolationPolicy.NO_INSERTS;
    QuotaSettings settings = QuotaSettingsFactory.limitTableSpace(tn, sizeLimit, violationPolicy);
    final Admin admin = TEST_UTIL.getAdmin();
    LOG.info("SET QUOTA");
    admin.setQuota(settings);
    final Connection conn = TEST_UTIL.getConnection();

    // Write enough data to invalidate the quota
    Put p = new Put(Bytes.toBytes("row1"));
    byte[] bytes = new byte[10];
    Arrays.fill(bytes, (byte) 2);
    for (int i = 0; i < 200; i++) {
      p.addColumn(Bytes.toBytes(FAM1), Bytes.toBytes("qual" + i), bytes);
    }
    conn.getTable(tn).put(p);
    admin.flush(tn);

    // Wait for the table to move into violation
    Waiter.waitFor(TEST_UTIL.getConfiguration(), 30000, 1000, new Waiter.Predicate<Exception>() {
      @Override
      public boolean evaluate() throws Exception {
        SpaceQuotaSnapshot snapshot = getSnapshotForTable(conn, tn);
        if (snapshot == null) {
          return false;
        }
        return snapshot.getQuotaStatus().isInViolation();
      }
    });

    // Close the region, prevent the server from sending new status reports.
    List<RegionInfo> regions = admin.getRegions(tn);
    assertEquals(1, regions.size());
    RegionInfo hri = regions.get(0);
    admin.unassign(hri.getRegionName(), true);

    // We should see this table move out of violation after the report expires.
    Waiter.waitFor(TEST_UTIL.getConfiguration(), 30000, 1000, new Waiter.Predicate<Exception>() {
      @Override
      public boolean evaluate() throws Exception {
        SpaceQuotaSnapshot snapshot = getSnapshotForTable(conn, tn);
        if (snapshot == null) {
          return false;
        }
        return !snapshot.getQuotaStatus().isInViolation();
      }
    });

    // The QuotaObserverChore's memory should also show it not in violation.
    final HMaster master = TEST_UTIL.getMiniHBaseCluster().getMaster();
    QuotaSnapshotStore<TableName> tableStore =
      master.getQuotaObserverChore().getTableSnapshotStore();
    SpaceQuotaSnapshot snapshot = tableStore.getCurrentState(tn);
    assertFalse("Quota should not be in violation", snapshot.getQuotaStatus().isInViolation());
  }
A test case to verify that region reports are expired when they are not sent.
hbase-server/src/test/java/org/apache/hadoop/hbase/quotas/TestQuotaObserverChoreRegionReports.java