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.util; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertNotNull; 022import static org.junit.jupiter.api.Assertions.assertThrows; 023import static org.junit.jupiter.api.Assertions.assertTrue; 024 025import java.io.IOException; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.fs.FileSystem; 028import org.apache.hadoop.fs.Path; 029import org.apache.hadoop.hbase.HBaseConfiguration; 030import org.apache.hadoop.hbase.testclassification.SmallTests; 031import org.junit.jupiter.api.Tag; 032import org.junit.jupiter.api.Test; 033import org.junit.jupiter.api.io.TempDir; 034 035/** 036 * Unit tests for {@link BackupFileSystemManager}. 037 */ 038@Tag(SmallTests.TAG) 039public class TestBackupFileSystemManager { 040 041 @TempDir 042 java.nio.file.Path tmp; 043 044 /** 045 * extractWalPathInfo: happy path where WALs dir has a prefix. e.g. 046 * /some/prefix/WALs/2025-09-14/some-wal 047 */ 048 @Test 049 public void testExtractWalPathInfo_withPrefix() throws Exception { 050 Path walPath = 051 new Path("/some/prefix/" + BackupFileSystemManager.WALS_DIR + "/2025-09-14/wal-000"); 052 BackupFileSystemManager.WalPathInfo info = BackupFileSystemManager.extractWalPathInfo(walPath); 053 054 assertNotNull(info, "WalPathInfo should not be null"); 055 // prefixBeforeWALs should be "/some/prefix" 056 assertEquals("/some/prefix", info.getPrefixBeforeWALs().toString()); 057 assertEquals("2025-09-14", info.getDateSegment()); 058 } 059 060 /** 061 * extractWalPathInfo: case where WALs is at root (leading slash). e.g. /WALs/2025-09-14/some-wal 062 * Expect prefixBeforeWALs to be "/" (root) or non-null; resolution should still work. 063 */ 064 @Test 065 public void testExtractWalPathInfo_rootWALs() throws Exception { 066 Path walPath = new Path("/" + BackupFileSystemManager.WALS_DIR + "/2025-09-14/wal-123"); 067 BackupFileSystemManager.WalPathInfo info = BackupFileSystemManager.extractWalPathInfo(walPath); 068 069 assertNotNull(info); 070 // parent of "/WALs" in Hadoop Path is "/" (root). Ensure date segment parsed. 071 assertEquals("2025-09-14", info.getDateSegment()); 072 assertNotNull(info.getPrefixBeforeWALs(), 073 "prefixBeforeWALs should not be null for root-style path"); 074 // prefix might be "/" (expected), be tolerant: assert it ends with "/" or equals "/" 075 assertTrue(info.getPrefixBeforeWALs().toString().equals("/") 076 || !info.getPrefixBeforeWALs().toString().isEmpty()); 077 } 078 079 /** 080 * extractWalPathInfo: null input should throw IllegalArgumentException. 081 */ 082 @Test 083 public void testExtractWalPathInfo_nullPath() throws Exception { 084 assertThrows(IllegalArgumentException.class, 085 () -> BackupFileSystemManager.extractWalPathInfo(null)); 086 } 087 088 /** 089 * extractWalPathInfo: missing date directory -> should throw IOException. Example: path that has 090 * no parent for the wal file. 091 */ 092 @Test 093 public void testExtractWalPathInfo_missingDateDir() throws Exception { 094 // A single segment path (no parents) e.g. "walfile" 095 Path walPath = new Path("walfile"); 096 assertThrows(IOException.class, () -> BackupFileSystemManager.extractWalPathInfo(walPath)); 097 } 098 099 /** 100 * extractWalPathInfo: WALs segment name mismatch -> should throw IOException. e.g. 101 * /prefix/NOT_WALs/2025/wal 102 */ 103 @Test 104 public void testExtractWalPathInfo_wrongWALsegment() throws Exception { 105 Path walPath = new Path("/prefix/NOT_WALS/2025/wal"); 106 assertThrows(IOException.class, () -> BackupFileSystemManager.extractWalPathInfo(walPath)); 107 } 108 109 /** 110 * resolveBulkLoadFullPath: normal case with prefix. 111 */ 112 @Test 113 public void testResolveBulkLoadFullPath_withPrefix() throws Exception { 114 Path walPath = 115 new Path("/some/prefix/" + BackupFileSystemManager.WALS_DIR + "/2025-08-30/wal-1"); 116 Path relative = new Path("namespace/table/region/family/file1"); 117 Path full = BackupFileSystemManager.resolveBulkLoadFullPath(walPath, relative); 118 119 // expected: /some/prefix/bulk-load-files/2025-08-30/namespace/table/region/family/file1 120 String expected = "/some/prefix/" + BackupFileSystemManager.BULKLOAD_FILES_DIR 121 + "/2025-08-30/namespace/table/region/family/file1"; 122 assertEquals(expected, full.toString()); 123 } 124 125 /** 126 * resolveBulkLoadFullPath: when WALs is under root (prefix is root) - ensure path resolved under 127 * /bulk-load-files/<date>/... 128 */ 129 @Test 130 public void testResolveBulkLoadFullPath_rootWALs() throws Exception { 131 Path walPath = new Path("/" + BackupFileSystemManager.WALS_DIR + "/2025-08-30/wal-2"); 132 Path relative = new Path("ns/tbl/r/f"); 133 Path full = BackupFileSystemManager.resolveBulkLoadFullPath(walPath, relative); 134 135 String expected = "/" + BackupFileSystemManager.BULKLOAD_FILES_DIR + "/2025-08-30/ns/tbl/r/f"; 136 assertEquals(expected, full.toString()); 137 } 138 139 /** 140 * Integration-y test: constructor should create directories under the provided backup root. Uses 141 * a temporary folder (local fs). 142 */ 143 @Test 144 public void testConstructorCreatesDirectories() throws Exception { 145 java.nio.file.Path root = tmp.resolve("backupRoot"); 146 java.nio.file.Files.createDirectories(root); 147 String rootPath = root.toString(); 148 149 Configuration conf = HBaseConfiguration.create(); 150 BackupFileSystemManager mgr = new BackupFileSystemManager("peer-1", conf, rootPath); 151 152 FileSystem fs = mgr.getBackupFs(); 153 Path wals = mgr.getWalsDir(); 154 Path bulk = mgr.getBulkLoadFilesDir(); 155 156 assertTrue(fs.exists(wals), "WALs dir should exist"); 157 assertTrue(fs.exists(bulk), "bulk-load-files dir should exist"); 158 } 159}