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.util; 019 020import static org.apache.hadoop.hbase.HConstants.HBASE_GLOBAL_READONLY_ENABLED_KEY; 021import static org.junit.jupiter.api.Assertions.assertArrayEquals; 022import static org.junit.jupiter.api.Assertions.assertEquals; 023import static org.junit.jupiter.api.Assertions.assertNotNull; 024import static org.junit.jupiter.api.Assertions.assertNull; 025import static org.junit.jupiter.api.Assertions.assertTrue; 026 027import java.util.Arrays; 028import java.util.List; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.coprocessor.CoprocessorHost; 031import org.apache.hadoop.hbase.security.access.BulkLoadReadOnlyController; 032import org.apache.hadoop.hbase.security.access.EndpointReadOnlyController; 033import org.apache.hadoop.hbase.security.access.MasterReadOnlyController; 034import org.apache.hadoop.hbase.security.access.RegionReadOnlyController; 035import org.apache.hadoop.hbase.security.access.RegionServerReadOnlyController; 036import org.apache.hadoop.hbase.testclassification.CoprocessorTests; 037import org.apache.hadoop.hbase.testclassification.SmallTests; 038import org.junit.jupiter.api.BeforeEach; 039import org.junit.jupiter.api.Tag; 040import org.junit.jupiter.api.Test; 041 042@Tag(CoprocessorTests.TAG) 043@Tag(SmallTests.TAG) 044public class TestCoprocessorConfigurationUtil { 045 046 private Configuration conf; 047 private String key; 048 049 @BeforeEach 050 public void setUp() { 051 conf = new Configuration(); 052 key = "test.key"; 053 } 054 055 @Test 056 public void testAddCoprocessorsEmptyCPList() { 057 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1", "cp2")); 058 assertArrayEquals(new String[] { "cp1", "cp2" }, conf.getStrings(key)); 059 } 060 061 @Test 062 public void testAddCoprocessorsNonEmptyCPList() { 063 conf.setStrings(key, "cp1"); 064 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1", "cp2")); 065 assertArrayEquals(new String[] { "cp1", "cp2" }, conf.getStrings(key)); 066 } 067 068 @Test 069 public void testAddCoprocessorsNoChange() { 070 conf.setStrings(key, "cp1"); 071 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1")); 072 assertArrayEquals(new String[] { "cp1" }, conf.getStrings(key)); 073 } 074 075 @Test 076 public void testAddCoprocessorsIdempotent() { 077 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1", "cp2")); 078 // Call again 079 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1", "cp2")); 080 assertArrayEquals(new String[] { "cp1", "cp2" }, conf.getStrings(key)); 081 } 082 083 @Test 084 public void testAddCoprocessorsIdempotentWithOverlap() { 085 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1")); 086 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp1", "cp2")); 087 CoprocessorConfigurationUtil.addCoprocessors(conf, key, List.of("cp2")); 088 assertArrayEquals(new String[] { "cp1", "cp2" }, conf.getStrings(key)); 089 } 090 091 @Test 092 public void testRemoveCoprocessorsEmptyCPList() { 093 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp1")); 094 assertNull(conf.getStrings(key)); 095 } 096 097 @Test 098 public void testRemoveCoprocessorsNonEmptyCPList() { 099 conf.setStrings(key, "cp1", "cp2", "cp3"); 100 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp2")); 101 assertArrayEquals(new String[] { "cp1", "cp3" }, conf.getStrings(key)); 102 } 103 104 @Test 105 public void testRemoveCoprocessorsNoChange() { 106 conf.setStrings(key, "cp1"); 107 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp2")); 108 assertArrayEquals(new String[] { "cp1" }, conf.getStrings(key)); 109 } 110 111 @Test 112 public void testRemoveCoprocessorsIdempotent() { 113 conf.setStrings(key, "cp1", "cp2"); 114 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp2")); 115 // Call again 116 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp2")); 117 assertArrayEquals(new String[] { "cp1" }, conf.getStrings(key)); 118 } 119 120 @Test 121 public void testRemoveCoprocessorsIdempotentWhenNotPresent() { 122 conf.setStrings(key, "cp1"); 123 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp2")); 124 CoprocessorConfigurationUtil.removeCoprocessors(conf, key, List.of("cp2")); 125 assertArrayEquals(new String[] { "cp1" }, conf.getStrings(key)); 126 } 127 128 private void assertEnableReadOnlyMode(String key, List<String> expected) { 129 conf.setBoolean(HBASE_GLOBAL_READONLY_ENABLED_KEY, true); 130 CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf, key); 131 String[] result = conf.getStrings(key); 132 assertNotNull(result); 133 assertEquals(expected.size(), result.length); 134 assertTrue(Arrays.asList(result).containsAll(expected)); 135 } 136 137 @Test 138 public void testSyncReadOnlyConfigurationsReadOnlyEnableAllKeys() { 139 assertEnableReadOnlyMode(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, 140 List.of(MasterReadOnlyController.class.getName())); 141 142 assertEnableReadOnlyMode(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, 143 List.of(RegionServerReadOnlyController.class.getName())); 144 assertEnableReadOnlyMode(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 145 List.of(RegionReadOnlyController.class.getName(), BulkLoadReadOnlyController.class.getName(), 146 EndpointReadOnlyController.class.getName())); 147 } 148 149 private void assertDisableReadOnlyMode(String key, List<String> initialCoprocs) { 150 conf.setStrings(key, initialCoprocs.toArray(new String[0])); 151 conf.setBoolean(HBASE_GLOBAL_READONLY_ENABLED_KEY, false); 152 CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf, key); 153 String[] result = conf.getStrings(key); 154 assertTrue(result == null || result.length == 0); 155 } 156 157 @Test 158 public void testSyncReadOnlyConfigurationsReadOnlyDisableAllKeys() { 159 assertDisableReadOnlyMode(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, 160 List.of(MasterReadOnlyController.class.getName())); 161 162 assertDisableReadOnlyMode(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, 163 List.of(RegionServerReadOnlyController.class.getName())); 164 165 assertDisableReadOnlyMode(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 166 List.of(RegionReadOnlyController.class.getName(), BulkLoadReadOnlyController.class.getName(), 167 EndpointReadOnlyController.class.getName())); 168 } 169 170 @Test 171 public void testSyncReadOnlyConfigurationsReadOnlyEnablePreservesExistingCoprocessors() { 172 String key = CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY; 173 conf.setStrings(key, "existingCp"); 174 conf.setBoolean(HBASE_GLOBAL_READONLY_ENABLED_KEY, true); 175 CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf, key); 176 List<String> result = Arrays.asList(conf.getStrings(key)); 177 assertTrue(result.contains("existingCp")); 178 assertTrue(result.contains(MasterReadOnlyController.class.getName())); 179 } 180 181 @Test 182 public void testSyncReadOnlyConfigurationsReadOnlyDisableRemovesOnlyReadOnlyCoprocessor() { 183 Configuration conf = new Configuration(false); 184 String key = CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY; 185 String existingCp = "org.example.OtherCP"; 186 conf.setStrings(key, existingCp, MasterReadOnlyController.class.getName()); 187 CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf, key); 188 String[] cps = conf.getStrings(key); 189 assertNotNull(cps); 190 assertEquals(1, cps.length); 191 assertEquals(existingCp, cps[0]); 192 } 193 194 @Test 195 public void testSyncReadOnlyConfigurationsIsIdempotent() { 196 Configuration conf = new Configuration(false); 197 conf.setBoolean(HBASE_GLOBAL_READONLY_ENABLED_KEY, true); 198 String key = CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY; 199 CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf, key); 200 CoprocessorConfigurationUtil.syncReadOnlyConfigurations(conf, key); 201 String[] cps = conf.getStrings(key); 202 assertNotNull(cps); 203 assertEquals(1, cps.length); 204 } 205}