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.apache.hadoop.hbase.coprocessor.CoprocessorHost.REGION_COPROCESSOR_CONF_KEY; 021import static org.junit.jupiter.api.Assertions.assertThrows; 022 023import java.io.IOException; 024import java.util.Optional; 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.HBaseConfiguration; 027import org.apache.hadoop.hbase.client.RegionInfo; 028import org.apache.hadoop.hbase.client.RegionInfoBuilder; 029import org.apache.hadoop.hbase.client.TableDescriptor; 030import org.apache.hadoop.hbase.client.TableDescriptorBuilder; 031import org.apache.hadoop.hbase.regionserver.FlushLifeCycleTracker; 032import org.apache.hadoop.hbase.regionserver.HRegion; 033import org.apache.hadoop.hbase.regionserver.InternalScanner; 034import org.apache.hadoop.hbase.regionserver.RegionCoprocessorHost; 035import org.apache.hadoop.hbase.regionserver.RegionServerServices; 036import org.apache.hadoop.hbase.regionserver.ScanType; 037import org.apache.hadoop.hbase.regionserver.Store; 038import org.apache.hadoop.hbase.regionserver.compactions.CompactionLifeCycleTracker; 039import org.apache.hadoop.hbase.regionserver.compactions.CompactionRequest; 040import org.apache.hadoop.hbase.testclassification.CoprocessorTests; 041import org.apache.hadoop.hbase.testclassification.SmallTests; 042import org.junit.jupiter.api.Tag; 043import org.junit.jupiter.api.Test; 044import org.mockito.Mockito; 045 046/** 047 * Test that we fail if a Coprocessor tries to return a null scanner out 048 * {@link RegionObserver#preFlush(ObserverContext, Store, InternalScanner, FlushLifeCycleTracker)} 049 * or 050 * {@link RegionObserver#preCompact(ObserverContext, Store, InternalScanner, ScanType, CompactionLifeCycleTracker, CompactionRequest)} 051 * @see <a href=https://issues.apache.org/jira/browse/HBASE-19122>HBASE-19122</a> 052 */ 053@Tag(CoprocessorTests.TAG) 054@Tag(SmallTests.TAG) 055public class TestRegionObserverPreFlushAndPreCompact { 056 057 /** 058 * Coprocessor that returns null when preCompact or preFlush is called. 059 */ 060 public static class TestRegionObserver implements RegionObserver, RegionCoprocessor { 061 @Override 062 public InternalScanner preFlush(ObserverContext<? extends RegionCoprocessorEnvironment> c, 063 Store store, InternalScanner scanner, FlushLifeCycleTracker tracker) throws IOException { 064 return null; 065 } 066 067 @Override 068 public InternalScanner preCompact(ObserverContext<? extends RegionCoprocessorEnvironment> c, 069 Store store, InternalScanner scanner, ScanType scanType, CompactionLifeCycleTracker tracker, 070 CompactionRequest request) throws IOException { 071 return null; 072 } 073 074 @Override 075 public Optional<RegionObserver> getRegionObserver() { 076 return Optional.of(this); 077 } 078 } 079 080 /** 081 * Ensure we get expected exception when we try to return null from a preFlush call. 082 * @throws IOException We expect it to throw {@link CoprocessorException} 083 */ 084 @Test 085 public void testPreFlushReturningNull() throws IOException { 086 RegionCoprocessorHost rch = getRegionCoprocessorHost(); 087 assertThrows(CoprocessorException.class, () -> rch.preFlush(null, null, null)); 088 } 089 090 /** 091 * Ensure we get expected exception when we try to return null from a preCompact call. 092 * @throws IOException We expect it to throw {@link CoprocessorException} 093 */ 094 @Test 095 public void testPreCompactReturningNull() throws IOException { 096 RegionCoprocessorHost rch = getRegionCoprocessorHost(); 097 assertThrows(CoprocessorException.class, 098 () -> rch.preCompact(null, null, null, null, null, null)); 099 } 100 101 private RegionCoprocessorHost getRegionCoprocessorHost() { 102 // Make up an HRegion instance. Use the hbase:meta first region as our RegionInfo. Use 103 // hbase:meta table name for building the TableDescriptor our mock returns when asked schema 104 // down inside RegionCoprocessorHost. Pass in mocked RegionServerServices too. 105 RegionInfo ri = RegionInfoBuilder.FIRST_META_REGIONINFO; 106 HRegion mockedHRegion = Mockito.mock(HRegion.class); 107 Mockito.when(mockedHRegion.getRegionInfo()).thenReturn(ri); 108 TableDescriptor td = TableDescriptorBuilder.newBuilder(ri.getTable()).build(); 109 Mockito.when(mockedHRegion.getTableDescriptor()).thenReturn(td); 110 RegionServerServices mockedServices = Mockito.mock(RegionServerServices.class); 111 Configuration conf = HBaseConfiguration.create(); 112 // Load our test coprocessor defined above. 113 conf.set(REGION_COPROCESSOR_CONF_KEY, TestRegionObserver.class.getName()); 114 return new RegionCoprocessorHost(mockedHRegion, mockedServices, conf); 115 } 116}