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.master.procedure;
019
020import static org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.SnapshotState.SNAPSHOT_SNAPSHOT_ONLINE_REGIONS;
021import static org.junit.Assert.assertTrue;
022
023import java.io.IOException;
024import java.util.Optional;
025import java.util.concurrent.TimeUnit;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.hbase.HBaseClassTestRule;
028import org.apache.hadoop.hbase.HBaseTestingUtil;
029import org.apache.hadoop.hbase.TableName;
030import org.apache.hadoop.hbase.client.Admin;
031import org.apache.hadoop.hbase.client.SnapshotDescription;
032import org.apache.hadoop.hbase.client.SnapshotType;
033import org.apache.hadoop.hbase.client.Table;
034import org.apache.hadoop.hbase.master.HMaster;
035import org.apache.hadoop.hbase.procedure2.Procedure;
036import org.apache.hadoop.hbase.procedure2.ProcedureSuspendedException;
037import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
038import org.apache.hadoop.hbase.procedure2.ProcedureYieldException;
039import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher;
040import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
041import org.apache.hadoop.hbase.testclassification.MasterTests;
042import org.apache.hadoop.hbase.testclassification.MediumTests;
043import org.apache.hadoop.hbase.util.Bytes;
044import org.apache.hadoop.hbase.util.RegionSplitter;
045import org.junit.After;
046import org.junit.Before;
047import org.junit.ClassRule;
048import org.junit.experimental.categories.Category;
049import org.mockito.Mockito;
050import org.mockito.internal.stubbing.answers.AnswersWithDelay;
051import org.mockito.invocation.InvocationOnMock;
052import org.mockito.stubbing.Answer;
053import org.slf4j.Logger;
054import org.slf4j.LoggerFactory;
055
056import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
057import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos;
058import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProcedureProtos.SnapshotState;
059import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos;
060
061@Category({ MasterTests.class, MediumTests.class })
062public class TestSnapshotProcedure {
063  protected static final Logger LOG = LoggerFactory.getLogger(TestSnapshotProcedure.class);
064
065  @ClassRule
066  public static final HBaseClassTestRule CLASS_RULE =
067    HBaseClassTestRule.forClass(TestSnapshotProcedure.class);
068
069  protected static HBaseTestingUtil TEST_UTIL;
070  protected HMaster master;
071  protected TableName TABLE_NAME;
072  protected byte[] CF;
073  protected String SNAPSHOT_NAME;
074  protected SnapshotDescription snapshot;
075  protected SnapshotProtos.SnapshotDescription snapshotProto;
076  protected Admin admin;
077
078  public static final class DelaySnapshotProcedure extends SnapshotProcedure {
079    public DelaySnapshotProcedure() {
080    }
081
082    public DelaySnapshotProcedure(final MasterProcedureEnv env,
083      final SnapshotProtos.SnapshotDescription snapshot) {
084      super(env, snapshot);
085    }
086
087    @Override
088    protected Flow executeFromState(MasterProcedureEnv env,
089      MasterProcedureProtos.SnapshotState state)
090      throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
091      Flow flow = super.executeFromState(env, state);
092      if (state == SNAPSHOT_SNAPSHOT_ONLINE_REGIONS) {
093        TimeUnit.SECONDS.sleep(20);
094      }
095      return flow;
096    }
097  }
098
099  @Before
100  public void setup() throws Exception {
101    TEST_UTIL = new HBaseTestingUtil();
102    Configuration config = TEST_UTIL.getConfiguration();
103    // using SnapshotVerifyProcedure to verify snapshot
104    config.setInt("hbase.snapshot.remote.verify.threshold", 1);
105    // disable info server. Info server is useful when we run unit tests locally, but it will
106    // fails integration testing of jenkins.
107    // config.setInt(HConstants.MASTER_INFO_PORT, 8080);
108
109    // delay dispatch so that we can do something, for example kill a target server
110    config.setInt(RemoteProcedureDispatcher.DISPATCH_DELAY_CONF_KEY, 10000);
111    config.setInt(RemoteProcedureDispatcher.DISPATCH_MAX_QUEUE_SIZE_CONF_KEY, 128);
112    TEST_UTIL.startMiniCluster(3);
113    master = TEST_UTIL.getHBaseCluster().getMaster();
114    admin = TEST_UTIL.getAdmin();
115    TABLE_NAME = TableName.valueOf(Bytes.toBytes("SPTestTable"));
116    CF = Bytes.toBytes("cf");
117    SNAPSHOT_NAME = "SnapshotProcedureTest";
118    snapshot = new SnapshotDescription(SNAPSHOT_NAME, TABLE_NAME, SnapshotType.FLUSH);
119    snapshotProto = ProtobufUtil.createHBaseProtosSnapshotDesc(snapshot);
120    snapshotProto = SnapshotDescriptionUtils.validate(snapshotProto, master.getConfiguration());
121    final byte[][] splitKeys = new RegionSplitter.HexStringSplit().split(10);
122    Table table = TEST_UTIL.createTable(TABLE_NAME, CF, splitKeys);
123    TEST_UTIL.loadTable(table, CF, false);
124  }
125
126  public <T extends Procedure<MasterProcedureEnv>> T
127    waitProcedureRunnableAndGetFirst(Class<T> clazz, long timeout) throws IOException {
128    TEST_UTIL.waitFor(timeout, () -> master.getProcedures().stream().anyMatch(clazz::isInstance));
129    Optional<T> procOpt = master.getMasterProcedureExecutor().getProcedures().stream()
130      .filter(clazz::isInstance).map(clazz::cast).findFirst();
131    assertTrue(procOpt.isPresent());
132    return procOpt.get();
133  }
134
135  protected SnapshotProcedure getDelayedOnSpecificStateSnapshotProcedure(SnapshotProcedure sp,
136    MasterProcedureEnv env, SnapshotState state)
137    throws ProcedureSuspendedException, ProcedureYieldException, InterruptedException {
138    SnapshotProcedure spySp = Mockito.spy(sp);
139    Mockito.doAnswer(new AnswersWithDelay(60000, new Answer<Object>() {
140      @Override
141      public Object answer(InvocationOnMock invocation) throws Throwable {
142        return invocation.callRealMethod();
143      }
144    })).when(spySp).executeFromState(env, state);
145    return spySp;
146  }
147
148  @After
149  public void teardown() throws Exception {
150    if (this.master != null) {
151      ProcedureTestingUtility.setKillAndToggleBeforeStoreUpdate(master.getMasterProcedureExecutor(),
152        false);
153    }
154    TEST_UTIL.shutdownMiniCluster();
155  }
156}