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.junit.jupiter.api.Assertions.assertEquals;
021import static org.mockito.ArgumentMatchers.argThat;
022import static org.mockito.Mockito.mock;
023import static org.mockito.Mockito.never;
024import static org.mockito.Mockito.verify;
025import static org.mockito.Mockito.when;
026
027import java.io.IOException;
028import java.util.List;
029import org.apache.hadoop.conf.Configuration;
030import org.apache.hadoop.fs.FileSystem;
031import org.apache.hadoop.fs.Path;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.backup.impl.BackupManifest;
034import org.apache.hadoop.hbase.backup.impl.BackupManifest.BackupImage;
035import org.apache.hadoop.hbase.testclassification.SmallTests;
036import org.junit.jupiter.api.Tag;
037import org.junit.jupiter.api.Test;
038import org.junit.jupiter.api.io.TempDir;
039
040@Tag(SmallTests.TAG)
041public class TestHBackupFileSystem {
042
043  private static final Path ROOT_DIR = new Path("/backup/root");
044  private static final String BACKUP_ID = "123";
045
046  @Test
047  public void testRootDirManifestPathConversion() throws IOException {
048    Path manifestPath =
049      HBackupFileSystem.getManifestPath(new Configuration(), ROOT_DIR, BACKUP_ID, false);
050    Path convertedRootDir = HBackupFileSystem.getRootDirFromBackupPath(manifestPath, BACKUP_ID);
051    assertEquals(ROOT_DIR, convertedRootDir);
052  }
053
054  // This test verifies the .tmp directory is skipped over when each subdirectory in the backup
055  // root dir is searched for its .backup.manifest file.
056  @Test
057  public void testGetAllBackupImagesSkipsTmpDir(@TempDir java.nio.file.Path tempDir)
058    throws IOException {
059    Configuration conf = new Configuration();
060    Path backupRootPath = new Path(tempDir.toUri());
061    FileSystem fs = FileSystem.get(backupRootPath.toUri(), conf);
062
063    TableName[] tables = new TableName[] { TableName.valueOf("test_table") };
064    String backupId1 = "backup_0001";
065    String backupId2 = "backup_0002";
066
067    BackupInfo info1 =
068      new BackupInfo(backupId1, BackupType.FULL, tables, backupRootPath.toString());
069    new BackupManifest(info1).store(conf);
070
071    BackupInfo info2 =
072      new BackupInfo(backupId2, BackupType.INCREMENTAL, tables, backupRootPath.toString());
073    new BackupManifest(info2).store(conf);
074
075    fs.mkdirs(new Path(backupRootPath, ".tmp"));
076
077    // Use fully-qualified Log4j2 names to avoid banned-import enforcer rule
078    org.apache.logging.log4j.core.Appender mockAppender =
079      mock(org.apache.logging.log4j.core.Appender.class);
080    when(mockAppender.getName()).thenReturn("mockAppender");
081    when(mockAppender.isStarted()).thenReturn(true);
082    org.apache.logging.log4j.core.Logger log4jLogger =
083      (org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager
084        .getLogger(HBackupFileSystem.class);
085    log4jLogger.addAppender(mockAppender);
086
087    try {
088      List<BackupImage> images = HBackupFileSystem.getAllBackupImages(conf, backupRootPath);
089
090      // The backupRoot/.tmp dir should not be checked for a .backup.manifest file because it will
091      // not have one. Verify an ERROR is not logged with the following message:
092      // Cannot load backup manifest from: /path/to/.tmp
093      verify(mockAppender, never())
094        .append(argThat((org.apache.logging.log4j.core.LogEvent event) -> event.getLevel()
095          .equals(org.apache.logging.log4j.Level.ERROR)
096          && event.getMessage().getFormattedMessage().contains("Cannot load backup manifest from: ")
097          && event.getMessage().getFormattedMessage().contains(".tmp")));
098
099      assertEquals(2, images.size());
100      assertEquals(backupId2, images.get(0).getBackupId());
101      assertEquals(backupId1, images.get(1).getBackupId());
102    } finally {
103      log4jLogger.removeAppender(mockAppender);
104    }
105  }
106}