001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.quotas; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertNotNull; 023import static org.junit.jupiter.api.Assertions.assertNull; 024import static org.junit.jupiter.api.Assertions.assertThrows; 025import static org.junit.jupiter.api.Assertions.assertTrue; 026import static org.junit.jupiter.api.Assertions.fail; 027 028import java.util.List; 029import java.util.concurrent.TimeUnit; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.testclassification.SmallTests; 032import org.junit.jupiter.api.Tag; 033import org.junit.jupiter.api.Test; 034 035import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 036import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos; 037import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos; 038import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Quotas; 039import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceLimitRequest; 040import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.SpaceQuota; 041import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.Throttle; 042import org.apache.hadoop.hbase.shaded.protobuf.generated.QuotaProtos.TimedQuota; 043 044/** 045 * Test class for {@link QuotaSettingsFactory}. 046 */ 047@Tag(SmallTests.TAG) 048public class TestQuotaSettingsFactory { 049 050 @Test 051 public void testAllQuotasAddedToList() { 052 final SpaceQuota spaceQuota = SpaceQuota.newBuilder().setSoftLimit(1024L * 1024L * 1024L * 50L) // 50G 053 .setViolationPolicy(QuotaProtos.SpaceViolationPolicy.DISABLE) // Disable the table 054 .build(); 055 final long readLimit = 1000; 056 final long writeLimit = 500; 057 final Throttle throttle = Throttle.newBuilder() 058 // 1000 read reqs/min 059 .setReadNum(TimedQuota.newBuilder().setSoftLimit(readLimit) 060 .setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build()) 061 // 500 write reqs/min 062 .setWriteNum(TimedQuota.newBuilder().setSoftLimit(writeLimit) 063 .setTimeUnit(HBaseProtos.TimeUnit.MINUTES).build()) 064 .build(); 065 final Quotas quotas = Quotas.newBuilder().setSpace(spaceQuota) // Set the FS quotas 066 .setThrottle(throttle) // Set some RPC limits 067 .build(); 068 final TableName tn = TableName.valueOf("my_table"); 069 List<QuotaSettings> settings = QuotaSettingsFactory.fromTableQuotas(tn, quotas); 070 assertEquals(3, settings.size()); 071 boolean seenRead = false; 072 boolean seenWrite = false; 073 boolean seenSpace = false; 074 for (QuotaSettings setting : settings) { 075 if (setting instanceof ThrottleSettings) { 076 ThrottleSettings throttleSettings = (ThrottleSettings) setting; 077 switch (throttleSettings.getThrottleType()) { 078 case READ_NUMBER: 079 assertFalse(seenRead, "Should not have multiple read quotas"); 080 assertEquals(readLimit, throttleSettings.getSoftLimit()); 081 assertEquals(TimeUnit.MINUTES, throttleSettings.getTimeUnit()); 082 assertEquals(tn, throttleSettings.getTableName()); 083 assertNull(throttleSettings.getUserName(), "Username should be null"); 084 assertNull(throttleSettings.getNamespace(), "Namespace should be null"); 085 assertNull(throttleSettings.getRegionServer(), "RegionServer should be null"); 086 seenRead = true; 087 break; 088 case WRITE_NUMBER: 089 assertFalse(seenWrite, "Should not have multiple write quotas"); 090 assertEquals(writeLimit, throttleSettings.getSoftLimit()); 091 assertEquals(TimeUnit.MINUTES, throttleSettings.getTimeUnit()); 092 assertEquals(tn, throttleSettings.getTableName()); 093 assertNull(throttleSettings.getUserName(), "Username should be null"); 094 assertNull(throttleSettings.getNamespace(), "Namespace should be null"); 095 assertNull(throttleSettings.getRegionServer(), "RegionServer should be null"); 096 seenWrite = true; 097 break; 098 default: 099 fail("Unexpected throttle type: " + throttleSettings.getThrottleType()); 100 } 101 } else if (setting instanceof SpaceLimitSettings) { 102 assertFalse(seenSpace, "Should not have multiple space quotas"); 103 SpaceLimitSettings spaceLimit = (SpaceLimitSettings) setting; 104 assertEquals(tn, spaceLimit.getTableName()); 105 assertNull(spaceLimit.getUserName(), "Username should be null"); 106 assertNull(spaceLimit.getNamespace(), "Namespace should be null"); 107 assertNull(spaceLimit.getRegionServer(), "RegionServer should be null"); 108 assertTrue(spaceLimit.getProto().hasQuota(), "SpaceLimitSettings should have a SpaceQuota"); 109 assertEquals(spaceQuota, spaceLimit.getProto().getQuota()); 110 seenSpace = true; 111 } else { 112 fail("Unexpected QuotaSettings implementation: " + setting.getClass()); 113 } 114 } 115 assertTrue(seenRead, "Should have seen a read quota"); 116 assertTrue(seenWrite, "Should have seen a write quota"); 117 assertTrue(seenSpace, "Should have seen a space quota"); 118 } 119 120 @Test 121 public void testNeitherTableNorNamespace() { 122 final SpaceQuota spaceQuota = SpaceQuota.newBuilder().setSoftLimit(1L) 123 .setViolationPolicy(QuotaProtos.SpaceViolationPolicy.DISABLE).build(); 124 assertThrows(IllegalArgumentException.class, 125 () -> QuotaSettingsFactory.fromSpace(null, null, spaceQuota)); 126 } 127 128 @Test 129 public void testBothTableAndNamespace() { 130 final SpaceQuota spaceQuota = SpaceQuota.newBuilder().setSoftLimit(1L) 131 .setViolationPolicy(QuotaProtos.SpaceViolationPolicy.DISABLE).build(); 132 assertThrows(IllegalArgumentException.class, 133 () -> QuotaSettingsFactory.fromSpace(TableName.valueOf("foo"), "bar", spaceQuota)); 134 } 135 136 @Test 137 public void testSpaceLimitSettings() { 138 final TableName tableName = TableName.valueOf("foo"); 139 final long sizeLimit = 1024L * 1024L * 1024L * 75; // 75GB 140 final SpaceViolationPolicy violationPolicy = SpaceViolationPolicy.NO_INSERTS; 141 QuotaSettings settings = 142 QuotaSettingsFactory.limitTableSpace(tableName, sizeLimit, violationPolicy); 143 assertNotNull(settings, "QuotaSettings should not be null"); 144 assertTrue(settings instanceof SpaceLimitSettings, 145 "Should be an instance of SpaceLimitSettings"); 146 SpaceLimitSettings spaceLimitSettings = (SpaceLimitSettings) settings; 147 SpaceLimitRequest protoRequest = spaceLimitSettings.getProto(); 148 assertTrue(protoRequest.hasQuota(), "Request should have a SpaceQuota"); 149 SpaceQuota quota = protoRequest.getQuota(); 150 assertEquals(sizeLimit, quota.getSoftLimit()); 151 assertEquals(violationPolicy, ProtobufUtil.toViolationPolicy(quota.getViolationPolicy())); 152 assertFalse(quota.getRemove(), "The remove attribute should be false"); 153 } 154 155 @Test 156 public void testSpaceLimitSettingsForDeletes() { 157 final String ns = "ns1"; 158 final TableName tn = TableName.valueOf("tn1"); 159 QuotaSettings nsSettings = QuotaSettingsFactory.removeNamespaceSpaceLimit(ns); 160 assertNotNull(nsSettings, "QuotaSettings should not be null"); 161 assertTrue(nsSettings instanceof SpaceLimitSettings, 162 "Should be an instance of SpaceLimitSettings"); 163 SpaceLimitRequest nsProto = ((SpaceLimitSettings) nsSettings).getProto(); 164 assertTrue(nsProto.hasQuota(), "Request should have a SpaceQuota"); 165 assertTrue(nsProto.getQuota().getRemove(), "The remove attribute should be true"); 166 167 QuotaSettings tableSettings = QuotaSettingsFactory.removeTableSpaceLimit(tn); 168 assertNotNull(tableSettings, "QuotaSettings should not be null"); 169 assertTrue(tableSettings instanceof SpaceLimitSettings, 170 "Should be an instance of SpaceLimitSettings"); 171 SpaceLimitRequest tableProto = ((SpaceLimitSettings) tableSettings).getProto(); 172 assertTrue(tableProto.hasQuota(), "Request should have a SpaceQuota"); 173 assertTrue(tableProto.getQuota().getRemove(), "The remove attribute should be true"); 174 } 175}