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 public ExpectedException thrown = ExpectedException.none(); 060 061 private static final Configuration CONF = HBaseConfiguration.create(); 062 static { 063 CONF.setStrings(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, 064 SystemCoprocessor.class.getName()); 065 CONF.setStrings(CoprocessorHost.REGIONSERVER_COPROCESSOR_CONF_KEY, 066 SystemCoprocessor.class.getName()); 067 CONF.setStrings(CoprocessorHost.REGION_COPROCESSOR_CONF_KEY, 068 SystemCoprocessor.class.getName()); 069 } 070 private static final TableName TABLENAME = TableName.valueOf("TestCoprocessorConfiguration"); 071 private static final HRegionInfo REGIONINFO = new HRegionInfo(TABLENAME); 072 private static final HTableDescriptor TABLEDESC = new HTableDescriptor(TABLENAME); 073 static { 074 try { 075 TABLEDESC.addCoprocessor(TableCoprocessor.class.getName()); 076 } catch (IOException e) { 077 throw new RuntimeException(e); 078 } 079 } 080 081 // use atomic types in case coprocessor loading is ever multithreaded, also 082 // so we can mutate them even though they are declared final here 083 private static final AtomicBoolean systemCoprocessorLoaded = new AtomicBoolean(); 084 private static final AtomicBoolean tableCoprocessorLoaded = new AtomicBoolean(); 085 086 public static class SystemCoprocessor implements MasterCoprocessor, RegionCoprocessor, 087 RegionServerCoprocessor { 088 @Override 089 public void start(CoprocessorEnvironment env) throws IOException { 090 systemCoprocessorLoaded.set(true); 091 } 092 093 @Override 094 public void stop(CoprocessorEnvironment env) throws IOException { } 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 @Test 108 public void testRegionCoprocessorHostDefaults() throws Exception { 109 Configuration conf = new Configuration(CONF); 110 HRegion region = mock(HRegion.class); 111 when(region.getRegionInfo()).thenReturn(REGIONINFO); 112 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 113 RegionServerServices rsServices = mock(RegionServerServices.class); 114 systemCoprocessorLoaded.set(false); 115 tableCoprocessorLoaded.set(false); 116 new RegionCoprocessorHost(region, rsServices, conf); 117 assertEquals("System coprocessors loading default was not honored", 118 CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED, systemCoprocessorLoaded.get()); 119 assertEquals("Table coprocessors loading default was not honored", 120 CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED && 121 CoprocessorHost.DEFAULT_USER_COPROCESSORS_ENABLED, tableCoprocessorLoaded.get()); 122 } 123 124 @Test 125 public void testRegionServerCoprocessorHostDefaults() throws Exception { 126 Configuration conf = new Configuration(CONF); 127 RegionServerServices rsServices = mock(RegionServerServices.class); 128 systemCoprocessorLoaded.set(false); 129 new RegionServerCoprocessorHost(rsServices, conf); 130 assertEquals("System coprocessors loading default was not honored", 131 CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED, systemCoprocessorLoaded.get()); 132 } 133 134 @Test 135 public void testMasterCoprocessorHostDefaults() throws Exception { 136 Configuration conf = new Configuration(CONF); 137 MasterServices masterServices = mock(MasterServices.class); 138 systemCoprocessorLoaded.set(false); 139 new MasterCoprocessorHost(masterServices, conf); 140 assertEquals("System coprocessors loading default was not honored", 141 CoprocessorHost.DEFAULT_COPROCESSORS_ENABLED, systemCoprocessorLoaded.get()); 142 } 143 144 @Test 145 public void testRegionCoprocessorHostAllDisabled() throws Exception { 146 Configuration conf = new Configuration(CONF); 147 conf.setBoolean(CoprocessorHost.COPROCESSORS_ENABLED_CONF_KEY, false); 148 HRegion region = mock(HRegion.class); 149 when(region.getRegionInfo()).thenReturn(REGIONINFO); 150 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 151 RegionServerServices rsServices = mock(RegionServerServices.class); 152 systemCoprocessorLoaded.set(false); 153 tableCoprocessorLoaded.set(false); 154 new RegionCoprocessorHost(region, rsServices, conf); 155 assertFalse("System coprocessors should not have been loaded", 156 systemCoprocessorLoaded.get()); 157 assertFalse("Table coprocessors should not have been loaded", 158 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", 174 systemCoprocessorLoaded.get()); 175 assertFalse("Table coprocessors should not have been loaded", 176 tableCoprocessorLoaded.get()); 177 } 178 179 /** 180 * Rough test that Coprocessor Environment is Read-Only. 181 * Just check a random CP and see that it returns a read-only config. 182 */ 183 @Test 184 public void testReadOnlyConfiguration() throws Exception { 185 Configuration conf = new Configuration(CONF); 186 HRegion region = mock(HRegion.class); 187 when(region.getRegionInfo()).thenReturn(REGIONINFO); 188 when(region.getTableDescriptor()).thenReturn(TABLEDESC); 189 RegionServerServices rsServices = mock(RegionServerServices.class); 190 RegionCoprocessorHost rcp = new RegionCoprocessorHost(region, rsServices, conf); 191 boolean found = false; 192 for (String cpStr: rcp.getCoprocessors()) { 193 CoprocessorEnvironment cpenv = rcp.findCoprocessorEnvironment(cpStr); 194 if (cpenv != null) { 195 found = true; 196 } 197 Configuration c = cpenv.getConfiguration(); 198 thrown.expect(UnsupportedOperationException.class); 199 c.set("one.two.three", "four.five.six"); 200 } 201 assertTrue("Should be at least one CP found", found); 202 } 203}