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