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 */ 018 019package org.apache.hadoop.hbase.master.cleaner; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.List; 024 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.HBaseClassTestRule; 027import org.apache.hadoop.hbase.HBaseTestingUtility; 028import org.apache.hadoop.hbase.Stoppable; 029import org.apache.hadoop.hbase.master.snapshot.SnapshotManager; 030import org.apache.hadoop.hbase.testclassification.MasterTests; 031import org.apache.hadoop.hbase.testclassification.SmallTests; 032import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; 033import org.junit.ClassRule; 034import org.junit.Test; 035import org.junit.experimental.categories.Category; 036import org.mockito.Mockito; 037import org.slf4j.Logger; 038import org.slf4j.LoggerFactory; 039 040import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos; 041 042 043/** 044 * Tests for SnapshotsCleanerChore 045 */ 046@Category({MasterTests.class, SmallTests.class}) 047public class TestSnapshotCleanerChore { 048 049 @ClassRule 050 public static final HBaseClassTestRule CLASS_RULE = 051 HBaseClassTestRule.forClass(TestSnapshotCleanerChore.class); 052 053 private static final Logger LOG = LoggerFactory.getLogger(TestSnapshotCleanerChore.class); 054 055 private static final HBaseTestingUtility HBASE_TESTING_UTILITY = new HBaseTestingUtility(); 056 057 private SnapshotManager snapshotManager; 058 059 private Configuration getSnapshotCleanerConf() { 060 Configuration conf = HBASE_TESTING_UTILITY.getConfiguration(); 061 conf.setInt("hbase.master.cleaner.snapshot.interval", 100); 062 return conf; 063 } 064 065 066 @Test 067 public void testSnapshotCleanerWithoutAnyCompletedSnapshot() throws IOException { 068 snapshotManager = Mockito.mock(SnapshotManager.class); 069 Stoppable stopper = new StoppableImplementation(); 070 Configuration conf = getSnapshotCleanerConf(); 071 SnapshotCleanerChore snapshotCleanerChore = 072 new SnapshotCleanerChore(stopper, conf, snapshotManager); 073 try { 074 snapshotCleanerChore.chore(); 075 } finally { 076 stopper.stop("Stopping Test Stopper"); 077 } 078 Mockito.verify(snapshotManager, Mockito.times(0)).deleteSnapshot(Mockito.any()); 079 } 080 081 @Test 082 public void testSnapshotCleanerWithNoTtlExpired() throws IOException { 083 snapshotManager = Mockito.mock(SnapshotManager.class); 084 Stoppable stopper = new StoppableImplementation(); 085 Configuration conf = getSnapshotCleanerConf(); 086 SnapshotCleanerChore snapshotCleanerChore = 087 new SnapshotCleanerChore(stopper, conf, snapshotManager); 088 List<SnapshotProtos.SnapshotDescription> snapshotDescriptionList = new ArrayList<>(); 089 snapshotDescriptionList.add(getSnapshotDescription(-2, "snapshot01", "table01", 090 EnvironmentEdgeManager.currentTime() - 100000)); 091 snapshotDescriptionList.add(getSnapshotDescription(10, "snapshot02", "table02", 092 EnvironmentEdgeManager.currentTime())); 093 Mockito.when(snapshotManager.getCompletedSnapshots()).thenReturn(snapshotDescriptionList); 094 try { 095 LOG.info("2 Snapshots are completed but TTL is not expired for any of them"); 096 snapshotCleanerChore.chore(); 097 } finally { 098 stopper.stop("Stopping Test Stopper"); 099 } 100 Mockito.verify(snapshotManager, Mockito.times(0)).deleteSnapshot(Mockito.any()); 101 } 102 103 @Test 104 public void testSnapshotCleanerWithSomeTtlExpired() throws IOException { 105 snapshotManager = Mockito.mock(SnapshotManager.class); 106 Stoppable stopper = new StoppableImplementation(); 107 Configuration conf = getSnapshotCleanerConf(); 108 SnapshotCleanerChore snapshotCleanerChore = 109 new SnapshotCleanerChore(stopper, conf, snapshotManager); 110 List<SnapshotProtos.SnapshotDescription> snapshotDescriptionList = new ArrayList<>(); 111 snapshotDescriptionList.add(getSnapshotDescription(10, "snapshot01", "table01", 1)); 112 snapshotDescriptionList.add(getSnapshotDescription(5, "snapshot02", "table02", 2)); 113 snapshotDescriptionList.add(getSnapshotDescription(30, "snapshot01", "table01", 114 EnvironmentEdgeManager.currentTime())); 115 snapshotDescriptionList.add(getSnapshotDescription(0, "snapshot02", "table02", 116 EnvironmentEdgeManager.currentTime())); 117 snapshotDescriptionList.add(getSnapshotDescription(40, "snapshot03", "table03", 118 EnvironmentEdgeManager.currentTime())); 119 Mockito.when(snapshotManager.getCompletedSnapshots()).thenReturn(snapshotDescriptionList); 120 try { 121 LOG.info("5 Snapshots are completed. TTL is expired for 2 them. Going to delete them"); 122 snapshotCleanerChore.chore(); 123 } finally { 124 stopper.stop("Stopping Test Stopper"); 125 } 126 Mockito.verify(snapshotManager, Mockito.times(2)).deleteSnapshot(Mockito.any()); 127 } 128 129 @Test 130 public void testSnapshotCleanerWithReadIOE() throws IOException { 131 snapshotManager = Mockito.mock(SnapshotManager.class); 132 Stoppable stopper = new StoppableImplementation(); 133 Configuration conf = new HBaseTestingUtility().getConfiguration(); 134 SnapshotCleanerChore snapshotCleanerChore = 135 new SnapshotCleanerChore(stopper, conf, snapshotManager); 136 Mockito.when(snapshotManager.getCompletedSnapshots()).thenThrow(IOException.class); 137 try { 138 LOG.info("While getting completed Snapshots, IOException would occur. Hence, No Snapshot" 139 + " should be deleted"); 140 snapshotCleanerChore.chore(); 141 } finally { 142 stopper.stop("Stopping Test Stopper"); 143 } 144 Mockito.verify(snapshotManager, Mockito.times(0)).deleteSnapshot(Mockito.any()); 145 } 146 147 @Test 148 public void testSnapshotChoreWithTtlOutOfRange() throws IOException { 149 snapshotManager = Mockito.mock(SnapshotManager.class); 150 Stoppable stopper = new StoppableImplementation(); 151 Configuration conf = getSnapshotCleanerConf(); 152 List<SnapshotProtos.SnapshotDescription> snapshotDescriptionList = new ArrayList<>(); 153 snapshotDescriptionList.add(getSnapshotDescription(Long.MAX_VALUE, "snapshot01", "table01", 1)); 154 snapshotDescriptionList.add(getSnapshotDescription(5, "snapshot02", "table02", 2)); 155 Mockito.when(snapshotManager.getCompletedSnapshots()).thenReturn(snapshotDescriptionList); 156 SnapshotCleanerChore snapshotCleanerChore = 157 new SnapshotCleanerChore(stopper, conf, snapshotManager); 158 try { 159 LOG.info("Snapshot Chore is disabled. No cleanup performed for Expired Snapshots"); 160 snapshotCleanerChore.chore(); 161 } finally { 162 stopper.stop("Stopping Test Stopper"); 163 } 164 Mockito.verify(snapshotManager, Mockito.times(1)).getCompletedSnapshots(); 165 } 166 167 private SnapshotProtos.SnapshotDescription getSnapshotDescription(final long ttl, 168 final String snapshotName, final String tableName, final long snapshotCreationTime) { 169 SnapshotProtos.SnapshotDescription.Builder snapshotDescriptionBuilder = 170 SnapshotProtos.SnapshotDescription.newBuilder(); 171 snapshotDescriptionBuilder.setTtl(ttl); 172 snapshotDescriptionBuilder.setName(snapshotName); 173 snapshotDescriptionBuilder.setTable(tableName); 174 snapshotDescriptionBuilder.setType(SnapshotProtos.SnapshotDescription.Type.FLUSH); 175 snapshotDescriptionBuilder.setCreationTime(snapshotCreationTime); 176 return snapshotDescriptionBuilder.build(); 177 } 178 179 /** 180 * Simple helper class that just keeps track of whether or not its stopped. 181 */ 182 private static class StoppableImplementation implements Stoppable { 183 184 private volatile boolean stop = false; 185 186 @Override 187 public void stop(String why) { 188 this.stop = true; 189 } 190 191 @Override 192 public boolean isStopped() { 193 return this.stop; 194 } 195 196 } 197 198}