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