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.backup;
019
020import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.CONF_CONTINUOUS_BACKUP_WAL_DIR;
021import static org.apache.hadoop.hbase.backup.BackupRestoreConstants.OPTION_ENABLE_CONTINUOUS_BACKUP;
022import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_ENABLED_DEFAULT;
023import static org.apache.hadoop.hbase.replication.regionserver.ReplicationMarkerChore.REPLICATION_MARKER_ENABLED_KEY;
024import static org.junit.jupiter.api.Assertions.assertEquals;
025import static org.junit.jupiter.api.Assertions.assertNotEquals;
026import static org.junit.jupiter.api.Assertions.assertTrue;
027
028import java.io.ByteArrayOutputStream;
029import java.io.PrintStream;
030import java.util.List;
031import org.apache.hadoop.fs.FileSystem;
032import org.apache.hadoop.fs.Path;
033import org.apache.hadoop.hbase.TableName;
034import org.apache.hadoop.hbase.backup.BackupInfo.BackupState;
035import org.apache.hadoop.hbase.backup.impl.BackupCommands;
036import org.apache.hadoop.hbase.backup.impl.BackupSystemTable;
037import org.apache.hadoop.hbase.client.Put;
038import org.apache.hadoop.hbase.testclassification.LargeTests;
039import org.apache.hadoop.hbase.util.Bytes;
040import org.apache.hadoop.util.ToolRunner;
041import org.junit.jupiter.api.Tag;
042import org.junit.jupiter.api.Test;
043import org.slf4j.Logger;
044import org.slf4j.LoggerFactory;
045
046import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
047
048@Tag(LargeTests.TAG)
049public class TestBackupDescribe extends TestBackupBase {
050
051  private static final Logger LOG = LoggerFactory.getLogger(TestBackupDescribe.class);
052
053  /**
054   * Verify that describe works as expected if incorrect backup Id is supplied.
055   * @throws Exception if creating the {@link BackupDriver} fails
056   */
057  @Test
058  public void testBackupDescribe() throws Exception {
059    LOG.info("test backup describe on a single table with data");
060
061    String[] args = new String[] { "describe", "backup_2" };
062    int ret = ToolRunner.run(conf1, new BackupDriver(), args);
063    assertTrue(ret < 0);
064
065    ByteArrayOutputStream baos = new ByteArrayOutputStream();
066    System.setErr(new PrintStream(baos));
067    args = new String[] { "progress" };
068    ToolRunner.run(TEST_UTIL.getConfiguration(), new BackupDriver(), args);
069
070    String output = baos.toString();
071    LOG.info("Output from progress: " + output);
072    assertTrue(output.indexOf(BackupCommands.NO_ACTIVE_SESSION_FOUND) >= 0);
073  }
074
075  @Test
076  public void testBackupSetCommandWithNonExistentTable() throws Exception {
077    String[] args = new String[] { "set", "add", "some_set", "table" };
078    // Run backup
079    int ret = ToolRunner.run(conf1, new BackupDriver(), args);
080    assertNotEquals(ret, 0);
081  }
082
083  @Test
084  public void testBackupDescribeCommand() throws Exception {
085    LOG.info("test backup describe on a single table with data: command-line");
086
087    List<TableName> tableList = Lists.newArrayList(table1);
088    String backupId = fullTableBackup(tableList);
089
090    LOG.info("backup complete");
091    assertTrue(checkSucceeded(backupId));
092
093    BackupInfo info = getBackupAdmin().getBackupInfo(backupId);
094    assertTrue(info.getState() == BackupState.COMPLETE);
095
096    ByteArrayOutputStream baos = new ByteArrayOutputStream();
097    System.setOut(new PrintStream(baos));
098
099    String[] args = new String[] { "describe", backupId };
100
101    // Run backup
102    int ret = ToolRunner.run(conf1, new BackupDriver(), args);
103    assertTrue(ret == 0);
104    String response = baos.toString();
105    assertTrue(response.indexOf(backupId) > 0);
106    assertTrue(response.indexOf("COMPLETE") > 0);
107    assertTrue(response.contains("IsContinuous=false"));
108
109    BackupSystemTable table = new BackupSystemTable(TEST_UTIL.getConnection());
110    BackupInfo status = table.readBackupInfo(backupId);
111    String desc = status.getShortDescription();
112    table.close();
113    assertTrue(response.indexOf(desc) >= 0);
114  }
115
116  @Test
117  public void testBackupDescribeCommandForContinuousBackup() throws Exception {
118    LOG.info("test backup describe on a single table with data: command-line");
119    Path root = TEST_UTIL.getDataTestDirOnTestFS();
120    Path backupWalDir = new Path(root, "testBackupDescribeCommand");
121    FileSystem fs = FileSystem.get(conf1);
122    fs.mkdirs(backupWalDir);
123    conf1.set(CONF_CONTINUOUS_BACKUP_WAL_DIR, backupWalDir.toString());
124    conf1.setBoolean(REPLICATION_MARKER_ENABLED_KEY, true);
125
126    try (BackupSystemTable table = new BackupSystemTable(TEST_UTIL.getConnection())) {
127      // Continuous backup
128      String[] backupArgs = new String[] { "create", BackupType.FULL.name(), BACKUP_ROOT_DIR, "-t",
129        table1.getNameAsString(), "-" + OPTION_ENABLE_CONTINUOUS_BACKUP };
130      int ret = ToolRunner.run(conf1, new BackupDriver(), backupArgs);
131      assertEquals(0, ret, "Backup should succeed");
132      List<BackupInfo> backups = table.getBackupHistory();
133      String backupId = backups.get(0).getBackupId();
134      assertTrue(checkSucceeded(backupId));
135      LOG.info("backup complete");
136
137      BackupInfo info = getBackupAdmin().getBackupInfo(backupId);
138      assertTrue(info.getState() == BackupState.COMPLETE);
139      ByteArrayOutputStream baos = new ByteArrayOutputStream();
140      System.setOut(new PrintStream(baos));
141
142      // Run backup describe
143      String[] args = new String[] { "describe", backupId };
144      ret = ToolRunner.run(conf1, new BackupDriver(), args);
145      assertTrue(ret == 0);
146      String response = baos.toString();
147      assertTrue(response.contains(backupId));
148      assertTrue(response.contains("COMPLETE"));
149      assertTrue(response.contains("IsContinuous=true"));
150      BackupInfo status = table.readBackupInfo(backupId);
151      String desc = status.getShortDescription();
152      assertTrue(response.contains(desc));
153
154      // load table
155      Put p;
156      for (int i = 0; i < NB_ROWS_IN_BATCH; i++) {
157        p = new Put(Bytes.toBytes("row" + i));
158        p.addColumn(famName, qualName, Bytes.toBytes("val" + i));
159        TEST_UTIL.getConnection().getTable(table1).put(p);
160      }
161      Thread.sleep(5000);
162
163      // Incremental backup
164      backupArgs = new String[] { "create", BackupType.INCREMENTAL.name(), BACKUP_ROOT_DIR, "-t",
165        table1.getNameAsString() };
166      ret = ToolRunner.run(conf1, new BackupDriver(), backupArgs);
167      assertEquals(0, ret, "Incremental Backup should succeed");
168      backups = table.getBackupHistory();
169      String incrBackupId = backups.get(0).getBackupId();
170      assertTrue(checkSucceeded(incrBackupId));
171      LOG.info("Incremental backup complete");
172
173      // Run backup describe
174      args = new String[] { "describe", incrBackupId };
175      ret = ToolRunner.run(conf1, new BackupDriver(), args);
176      assertTrue(ret == 0);
177      response = baos.toString();
178      assertTrue(response.contains(incrBackupId));
179      assertTrue(response.contains("COMPLETE"));
180      assertTrue(response.contains("Committed WAL time for incremental backup="));
181      status = table.readBackupInfo(incrBackupId);
182      desc = status.getShortDescription();
183      assertTrue(response.contains(desc));
184    } finally {
185      if (fs.exists(backupWalDir)) {
186        fs.delete(backupWalDir, true);
187      }
188      conf1.unset(CONF_CONTINUOUS_BACKUP_WAL_DIR);
189      conf1.setBoolean(REPLICATION_MARKER_ENABLED_KEY, REPLICATION_MARKER_ENABLED_DEFAULT);
190    }
191  }
192}