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.coprocessor; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertFalse; 022import static org.junit.jupiter.api.Assertions.assertThrows; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024import static org.mockito.Mockito.mock; 025import static org.mockito.Mockito.when; 026 027import java.io.IOException; 028import java.util.concurrent.atomic.AtomicBoolean; 029import org.apache.hadoop.conf.Configuration; 030import org.apache.hadoop.hbase.CoprocessorEnvironment; 031import org.apache.hadoop.hbase.HBaseConfiguration; 032import org.apache.hadoop.hbase.TableName; 033import org.apache.hadoop.hbase.client.RegionInfo; 034import org.apache.hadoop.hbase.client.RegionInfoBuilder; 035import org.apache.hadoop.hbase.client.TableDescriptor; 036import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 037import org.apache.hadoop.hbase.master.MasterCoprocessorHost; 038import org.apache.hadoop.hbase.master.MasterServices; 039import org.apache.hadoop.hbase.regionserver.HRegion; 040import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost; 041import org.apache.hadoop.hbase.regionserver.RegionServerCoprocessorHost; 042import org.apache.hadoop.hbase.regionserver.RegionServerServices; 043import org.apache.hadoop.hbase.testclassification.CoprocessorTests; 044import org.apache.hadoop.hbase.testclassification.SmallTests; 045import org.junit.jupiter.api.Tag; 046import org.junit.jupiter.api.Test; 047 048/** 049 * Tests for global coprocessor loading configuration 050 */ 051@Tag(CoprocessorTests.TAG) 052@Tag(SmallTests.TAG) 053public class TestCoprocessorConfiguration { 054 055 private static final Configuration CONF = HBaseConfiguration.create(); 056 static { 057 CONF.setStrings(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, SystemCoprocessor.class.getName()); 058 CONF.setStrings(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, 059 SystemCoprocessor.class.getName()); 060 CONF.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, SystemCoprocessor.class.getName()); 061 } 062 private static final TableName TABLENAME = TableName.valueOf("TestCoprocessorConfiguration"); 063 private static final RegionInfo REGIONINFO = RegionInfoBuilder.newBuilder(TABLENAME).build(); 064 private static final TableDescriptor TABLEDESC; 065 static { 066 try { 067 TABLEDESC = TableDescriptorBuilder.newBuilder(TABLENAME) 068 .setCoprocessor(TableCoprocessor.class.getName()).build(); 069 } catch (IOException e) { 070 throw new RuntimeException(e); 071 } 072 } 073 074 // use atomic types in case coprocessor loading is ever multithreaded, also 075 // so we can mutate them even though they are declared final here 076 private static final AtomicBoolean systemCoprocessorLoaded = new AtomicBoolean(); 077 private static final AtomicBoolean tableCoprocessorLoaded = new AtomicBoolean(); 078 079 public static class SystemCoprocessor 080 implements MasterCoprocessor, RegionCoprocessor, RegionServerCoprocessor { 081 @Override 082 public void start(CoprocessorEnvironment env) throws IOException { 083 systemCoprocessorLoaded.set(true); 084 } 085 086 @Override 087 public void stop(CoprocessorEnvironment env) throws IOException { 088 } 089 } 090 091 public static class TableCoprocessor implements RegionCoprocessor { 092 @Override 093 public void start(CoprocessorEnvironment env) throws IOException { 094 tableCoprocessorLoaded.set(true); 095 } 096 097 @Override 098 public void stop(CoprocessorEnvironment env) throws IOException { 099 } 100 } 101 102 @Test 103 public void testRegionCoprocessorHostDefaults() throws Exception { 104 Configuration conf = new Configuration(CONF); 105 HRegion region = mock(HRegion.class); 106 when(region.getRegionInfo()).thenReturn(REGIONINFO); 107 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 108 RegionServerServices rsServices = mock(RegionServerServices.class); 109 systemCoprocessorLoaded.set(false); 110 tableCoprocessorLoaded.set(false); 111 new RegionCoprocessorHost(region, rsServices, conf); 112 assertEquals(CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED, systemCoprocessorLoaded.get(), 113 "System coprocessors loading default was not honored"); 114 assertEquals( 115 CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED 116 && CoprocessorHost.DEFAULT_USER_COPROCESSORS_ENABLED, 117 tableCoprocessorLoaded.get(), "Table coprocessors loading default was not honored"); 118 } 119 120 @Test 121 public void testRegionServerCoprocessorHostDefaults() throws Exception { 122 Configuration conf = new Configuration(CONF); 123 RegionServerServices rsServices = mock(RegionServerServices.class); 124 systemCoprocessorLoaded.set(false); 125 new RegionServerCoprocessorHost(rsServices, conf); 126 assertEquals(CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED, systemCoprocessorLoaded.get(), 127 "System coprocessors loading default was not honored"); 128 } 129 130 @Test 131 public void testMasterCoprocessorHostDefaults() throws Exception { 132 Configuration conf = new Configuration(CONF); 133 MasterServices masterServices = mock(MasterServices.class); 134 systemCoprocessorLoaded.set(false); 135 new MasterCoprocessorHost(masterServices, conf); 136 assertEquals(CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED, systemCoprocessorLoaded.get(), 137 "System coprocessors loading default was not honored"); 138 } 139 140 @Test 141 public void testRegionCoprocessorHostAllDisabled() throws Exception { 142 Configuration conf = new Configuration(CONF); 143 conf.setBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY, false); 144 HRegion region = mock(HRegion.class); 145 when(region.getRegionInfo()).thenReturn(REGIONINFO); 146 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 147 RegionServerServices rsServices = mock(RegionServerServices.class); 148 systemCoprocessorLoaded.set(false); 149 tableCoprocessorLoaded.set(false); 150 new RegionCoprocessorHost(region, rsServices, conf); 151 assertFalse(systemCoprocessorLoaded.get(), "System coprocessors should not have been loaded"); 152 assertFalse(tableCoprocessorLoaded.get(), "Table coprocessors should not have been loaded"); 153 } 154 155 @Test 156 public void testRegionCoprocessorHostTableLoadingDisabled() throws Exception { 157 Configuration conf = new Configuration(CONF); 158 conf.setBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY, true); // if defaults change 159 conf.setBoolean(CoprocessorHost.USER_COPROCESSORS_ENABLED_CONF_KEY, false); 160 HRegion region = mock(HRegion.class); 161 when(region.getRegionInfo()).thenReturn(REGIONINFO); 162 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 163 RegionServerServices rsServices = mock(RegionServerServices.class); 164 systemCoprocessorLoaded.set(false); 165 tableCoprocessorLoaded.set(false); 166 new RegionCoprocessorHost(region, rsServices, conf); 167 assertTrue(systemCoprocessorLoaded.get(), "System coprocessors should have been loaded"); 168 assertFalse(tableCoprocessorLoaded.get(), "Table coprocessors should not have been loaded"); 169 } 170 171 /** 172 * Rough test that Coprocessor Environment is Read-Only. Just check a random CP and see that it 173 * returns a read-only config. 174 */ 175 @Test 176 public void testReadOnlyConfiguration() throws Exception { 177 Configuration conf = new Configuration(CONF); 178 HRegion region = mock(HRegion.class); 179 when(region.getRegionInfo()).thenReturn(REGIONINFO); 180 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 181 RegionServerServices rsServices = mock(RegionServerServices.class); 182 RegionCoprocessorHost rcp = new RegionCoprocessorHost(region, rsServices, conf); 183 boolean found = false; 184 for (String cpStr : rcp.getCoprocessors()) { 185 CoprocessorEnvironment cpenv = rcp.findCoprocessorEnvironment(cpStr); 186 if (cpenv != null) { 187 found = true; 188 } 189 Configuration c = cpenv.getConfiguration(); 190 assertThrows(UnsupportedOperationException.class, 191 () -> c.set("one.two.three", "four.five.six")); 192 } 193 assertTrue(found, "Should be at least one CP found"); 194 } 195}