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.snapshot;
019
020import static org.junit.Assert.assertFalse;
021import static org.junit.Assert.assertTrue;
022import static org.junit.Assert.fail;
023
024import java.io.IOException;
025import java.net.URI;
026import org.apache.hadoop.conf.Configuration;
027import org.apache.hadoop.fs.FileSystem;
028import org.apache.hadoop.fs.Path;
029import org.apache.hadoop.hbase.HBaseClassTestRule;
030import org.apache.hadoop.hbase.HBaseConfiguration;
031import org.apache.hadoop.hbase.HBaseTestingUtil;
032import org.apache.hadoop.hbase.HConstants;
033import org.apache.hadoop.hbase.testclassification.RegionServerTests;
034import org.apache.hadoop.hbase.testclassification.SmallTests;
035import org.apache.hadoop.hbase.util.EnvironmentEdgeManagerTestHelper;
036import org.junit.After;
037import org.junit.BeforeClass;
038import org.junit.ClassRule;
039import org.junit.Test;
040import org.junit.experimental.categories.Category;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044import org.apache.hadoop.hbase.shaded.protobuf.generated.SnapshotProtos.SnapshotDescription;
045
046/**
047 * Test that the {@link SnapshotDescription} helper is helping correctly.
048 */
049@Category({ RegionServerTests.class, SmallTests.class })
050public class TestSnapshotDescriptionUtils {
051
052  @ClassRule
053  public static final HBaseClassTestRule CLASS_RULE =
054    HBaseClassTestRule.forClass(TestSnapshotDescriptionUtils.class);
055
056  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
057  private static FileSystem fs;
058  private static Path root;
059
060  @BeforeClass
061  public static void setupFS() throws Exception {
062    fs = UTIL.getTestFileSystem();
063    root = new Path(UTIL.getDataTestDir(), "hbase");
064  }
065
066  @After
067  public void cleanupFS() throws Exception {
068    if (fs.exists(root)) {
069      if (!fs.delete(root, true)) {
070        throw new IOException("Failed to delete root test dir: " + root);
071      }
072      if (!fs.mkdirs(root)) {
073        throw new IOException("Failed to create root test dir: " + root);
074      }
075    }
076    EnvironmentEdgeManagerTestHelper.reset();
077  }
078
079  private static final Logger LOG = LoggerFactory.getLogger(TestSnapshotDescriptionUtils.class);
080
081  @Test
082  public void testValidateMissingTableName() throws IOException {
083    Configuration conf = new Configuration(false);
084    try {
085      SnapshotDescriptionUtils.validate(SnapshotDescription.newBuilder().setName("fail").build(),
086        conf);
087      fail("Snapshot was considered valid without a table name");
088    } catch (IllegalArgumentException e) {
089      LOG.debug("Correctly failed when snapshot doesn't have a tablename");
090    }
091  }
092
093  /**
094   * Test that we throw an exception if there is no working snapshot directory when we attempt to
095   * 'complete' the snapshot
096   * @throws Exception on failure
097   */
098  @Test
099  public void testCompleteSnapshotWithNoSnapshotDirectoryFailure() throws Exception {
100    Path snapshotDir = new Path(root, HConstants.SNAPSHOT_DIR_NAME);
101    Path tmpDir = new Path(snapshotDir, ".tmp");
102    Path workingDir = new Path(tmpDir, "not_a_snapshot");
103    Configuration conf = new Configuration();
104    FileSystem workingFs = workingDir.getFileSystem(conf);
105    assertFalse(
106      "Already have working snapshot dir: " + workingDir + " but shouldn't. Test file leak?",
107      fs.exists(workingDir));
108    SnapshotDescription snapshot = SnapshotDescription.newBuilder().setName("snapshot").build();
109    Path finishedDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshot, snapshotDir);
110
111    try {
112      SnapshotDescriptionUtils.completeSnapshot(finishedDir, workingDir, fs, workingFs, conf);
113      fail("Shouldn't successfully complete move of a non-existent directory.");
114    } catch (IOException e) {
115      LOG.info("Correctly failed to move non-existant directory: " + e.getMessage());
116    }
117  }
118
119  @Test
120  public void testIsSubDirectoryWorks() {
121    Path rootDir = new Path("hdfs://root/.hbase-snapshot/");
122
123    assertFalse(SnapshotDescriptionUtils.isSubDirectoryOf(rootDir, rootDir));
124    assertFalse(SnapshotDescriptionUtils
125      .isSubDirectoryOf(new Path("hdfs://root/.hbase-snapshotdir"), rootDir));
126    assertFalse(
127      SnapshotDescriptionUtils.isSubDirectoryOf(new Path("hdfs://root/.hbase-snapshot"), rootDir));
128    assertFalse(
129      SnapshotDescriptionUtils.isSubDirectoryOf(new Path("hdfs://.hbase-snapshot"), rootDir));
130    assertFalse(
131      SnapshotDescriptionUtils.isSubDirectoryOf(new Path("hdfs://.hbase-snapshot/.tmp"), rootDir));
132    assertFalse(SnapshotDescriptionUtils.isSubDirectoryOf(new Path("hdfs://root"), rootDir));
133    assertTrue(SnapshotDescriptionUtils
134      .isSubDirectoryOf(new Path("hdfs://root/.hbase-snapshot/.tmp"), rootDir));
135    assertTrue(SnapshotDescriptionUtils
136      .isSubDirectoryOf(new Path("hdfs://root/.hbase-snapshot/.tmp/snapshot"), rootDir));
137
138    assertFalse(
139      SnapshotDescriptionUtils.isSubDirectoryOf(new Path("s3://root/.hbase-snapshot/"), rootDir));
140    assertFalse(SnapshotDescriptionUtils.isSubDirectoryOf(new Path("s3://root"), rootDir));
141    assertFalse(SnapshotDescriptionUtils
142      .isSubDirectoryOf(new Path("s3://root/.hbase-snapshot/.tmp/snapshot"), rootDir));
143  }
144
145  @Test
146  public void testIsWithinWorkingDir() throws IOException {
147    Configuration conf = new Configuration();
148    conf.set(HConstants.HBASE_DIR, "hdfs://localhost/root/");
149
150    assertFalse(
151      SnapshotDescriptionUtils.isWithinDefaultWorkingDir(new Path("hdfs://localhost/root/"), conf));
152    assertFalse(SnapshotDescriptionUtils
153      .isWithinDefaultWorkingDir(new Path("hdfs://localhost/root/.hbase-snapshotdir"), conf));
154    assertFalse(SnapshotDescriptionUtils
155      .isWithinDefaultWorkingDir(new Path("hdfs://localhost/root/.hbase-snapshot"), conf));
156    assertFalse(SnapshotDescriptionUtils
157      .isWithinDefaultWorkingDir(new Path("hdfs://localhost/.hbase-snapshot"), conf));
158    assertFalse(SnapshotDescriptionUtils
159      .isWithinDefaultWorkingDir(new Path("hdfs://localhost/.hbase-snapshot/.tmp"), conf));
160    assertFalse(
161      SnapshotDescriptionUtils.isWithinDefaultWorkingDir(new Path("hdfs://localhost/root"), conf));
162    assertTrue(SnapshotDescriptionUtils
163      .isWithinDefaultWorkingDir(new Path("hdfs://localhost/root/.hbase-snapshot/.tmp"), conf));
164    assertTrue(SnapshotDescriptionUtils.isWithinDefaultWorkingDir(
165      new Path("hdfs://localhost/root/.hbase-snapshot/.tmp/snapshot"), conf));
166
167    assertFalse(SnapshotDescriptionUtils
168      .isWithinDefaultWorkingDir(new Path("s3://localhost/root/.hbase-snapshot/"), conf));
169    assertFalse(
170      SnapshotDescriptionUtils.isWithinDefaultWorkingDir(new Path("s3://localhost/root"), conf));
171    assertFalse(SnapshotDescriptionUtils.isWithinDefaultWorkingDir(
172      new Path("s3://localhost/root/.hbase-snapshot/.tmp/snapshot"), conf));
173
174    // for local mode
175    conf = HBaseConfiguration.create();
176    String hbsaeDir = conf.get(HConstants.HBASE_DIR);
177
178    assertFalse(
179      SnapshotDescriptionUtils.isWithinDefaultWorkingDir(new Path("file:" + hbsaeDir + "/"), conf));
180    assertFalse(SnapshotDescriptionUtils
181      .isWithinDefaultWorkingDir(new Path("file:" + hbsaeDir + "/.hbase-snapshotdir"), conf));
182    assertFalse(SnapshotDescriptionUtils
183      .isWithinDefaultWorkingDir(new Path("file:" + hbsaeDir + "/.hbase-snapshot"), conf));
184    assertFalse(
185      SnapshotDescriptionUtils.isWithinDefaultWorkingDir(new Path("file:/.hbase-snapshot"), conf));
186    assertFalse(SnapshotDescriptionUtils
187      .isWithinDefaultWorkingDir(new Path("file:/.hbase-snapshot/.tmp"), conf));
188    assertFalse(
189      SnapshotDescriptionUtils.isWithinDefaultWorkingDir(new Path("file:" + hbsaeDir), conf));
190    assertTrue(SnapshotDescriptionUtils
191      .isWithinDefaultWorkingDir(new Path("file:" + hbsaeDir + "/.hbase-snapshot/.tmp"), conf));
192    assertTrue(SnapshotDescriptionUtils.isWithinDefaultWorkingDir(
193      new Path("file:" + hbsaeDir + "/.hbase-snapshot/.tmp/snapshot"), conf));
194  }
195
196  @Test
197  public void testShouldSkipRenameSnapshotDirectories() {
198    URI workingDirURI = URI.create("/User/test1");
199    URI rootDirURI = URI.create("hdfs:///User/test2");
200
201    // should skip rename if it's not the same scheme;
202    assertTrue(
203      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
204
205    workingDirURI = URI.create("/User/test1");
206    rootDirURI = URI.create("file:///User/test2");
207    assertTrue(
208      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
209
210    // skip rename when either scheme or authority are the not same
211    workingDirURI = URI.create("hdfs://localhost:8020/User/test1");
212    rootDirURI = URI.create("hdfs://otherhost:8020/User/test2");
213    assertTrue(
214      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
215
216    workingDirURI = URI.create("file:///User/test1");
217    rootDirURI = URI.create("hdfs://localhost:8020/User/test2");
218    assertTrue(
219      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
220
221    workingDirURI = URI.create("hdfs:///User/test1");
222    rootDirURI = URI.create("hdfs:///User/test2");
223    assertFalse(
224      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
225
226    workingDirURI = URI.create("hdfs://localhost:8020/User/test1");
227    rootDirURI = URI.create("hdfs://localhost:8020/User/test2");
228    assertFalse(
229      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
230
231    workingDirURI = URI.create("hdfs://user:password@localhost:8020/User/test1");
232    rootDirURI = URI.create("hdfs://user:password@localhost:8020/User/test2");
233    assertFalse(
234      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
235
236    // skip rename when user information is not the same
237    workingDirURI = URI.create("hdfs://user:password@localhost:8020/User/test1");
238    rootDirURI = URI.create("hdfs://user2:password2@localhost:8020/User/test2");
239    assertTrue(
240      SnapshotDescriptionUtils.shouldSkipRenameSnapshotDirectories(workingDirURI, rootDirURI));
241  }
242
243}