blob: dd8ec697b65026ce9653a6eb1ba3b667db264b89 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.tools;
import java.util.Collections;
import org.junit.Assert;
import org.junit.Test;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.tools.DistCpOptions.FileAttribute;
import static org.apache.hadoop.test.GenericTestUtils.assertExceptionContains;
import static org.apache.hadoop.tools.DistCpOptions.MAX_NUM_LISTSTATUS_THREADS;
import static org.junit.Assert.fail;
/**
* This is to test constructing {@link DistCpOptions} manually with setters.
*
* The test cases in this class is very similar to the parser test, see
* {@link TestOptionsParser}.
*/
public class TestDistCpOptions {
private static final float DELTA = 0.001f;
@Test
public void testSetIgnoreFailure() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldIgnoreFailures());
builder.withIgnoreFailures(true);
Assert.assertTrue(builder.build().shouldIgnoreFailures());
}
@Test
public void testSetOverwrite() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldOverwrite());
builder.withOverwrite(true);
Assert.assertTrue(builder.build().shouldOverwrite());
try {
builder.withSyncFolder(true).build();
Assert.fail("Update and overwrite aren't allowed together");
} catch (IllegalArgumentException ignore) {
}
}
@Test
public void testLogPath() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertNull(builder.build().getLogPath());
final Path logPath = new Path("hdfs://localhost:8020/logs");
builder.withLogPath(logPath);
Assert.assertEquals(logPath, builder.build().getLogPath());
}
@Test
public void testSetBlokcing() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertTrue(builder.build().shouldBlock());
builder.withBlocking(false);
Assert.assertFalse(builder.build().shouldBlock());
}
@Test
public void testSetBandwidth() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertEquals(0, builder.build().getMapBandwidth(), DELTA);
builder.withMapBandwidth(11);
Assert.assertEquals(11, builder.build().getMapBandwidth(), DELTA);
}
@Test(expected = IllegalArgumentException.class)
public void testSetNonPositiveBandwidth() {
new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withMapBandwidth(-11)
.build();
}
@Test(expected = IllegalArgumentException.class)
public void testSetZeroBandwidth() {
new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withMapBandwidth(0)
.build();
}
@Test
public void testSetSkipCRC() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldSkipCRC());
final DistCpOptions options = builder.withSyncFolder(true).withCRC(true)
.build();
Assert.assertTrue(options.shouldSyncFolder());
Assert.assertTrue(options.shouldSkipCRC());
}
@Test
public void testSetAtomicCommit() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldAtomicCommit());
builder.withAtomicCommit(true);
Assert.assertTrue(builder.build().shouldAtomicCommit());
try {
builder.withSyncFolder(true).build();
Assert.fail("Atomic and sync folders were mutually exclusive");
} catch (IllegalArgumentException ignore) {
}
}
@Test
public void testSetWorkPath() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertNull(builder.build().getAtomicWorkPath());
builder.withAtomicCommit(true);
Assert.assertNull(builder.build().getAtomicWorkPath());
final Path workPath = new Path("hdfs://localhost:8020/work");
builder.withAtomicWorkPath(workPath);
Assert.assertEquals(workPath, builder.build().getAtomicWorkPath());
}
@Test
public void testSetSyncFolders() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldSyncFolder());
builder.withSyncFolder(true);
Assert.assertTrue(builder.build().shouldSyncFolder());
}
@Test
public void testSetDeleteMissing() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldDeleteMissing());
DistCpOptions options = builder.withSyncFolder(true)
.withDeleteMissing(true)
.build();
Assert.assertTrue(options.shouldSyncFolder());
Assert.assertTrue(options.shouldDeleteMissing());
options = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withOverwrite(true)
.withDeleteMissing(true)
.build();
Assert.assertTrue(options.shouldOverwrite());
Assert.assertTrue(options.shouldDeleteMissing());
try {
new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withDeleteMissing(true)
.build();
fail("Delete missing should fail without update or overwrite options");
} catch (IllegalArgumentException e) {
assertExceptionContains("Delete missing is applicable only with update " +
"or overwrite options", e);
}
try {
new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withSyncFolder(true)
.withDeleteMissing(true)
.withUseDiff("s1", "s2")
.build();
fail("Should have failed as -delete and -diff are mutually exclusive.");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"-delete and -diff/-rdiff are mutually exclusive.", e);
}
}
@Test
public void testSetMaps() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertEquals(DistCpConstants.DEFAULT_MAPS,
builder.build().getMaxMaps());
builder.maxMaps(1);
Assert.assertEquals(1, builder.build().getMaxMaps());
builder.maxMaps(0);
Assert.assertEquals(1, builder.build().getMaxMaps());
}
@Test
public void testSetNumListtatusThreads() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"));
// If command line argument isn't set, we expect .getNumListstatusThreads
// option to be zero (so that we know when to override conf properties).
Assert.assertEquals(0, builder.build().getNumListstatusThreads());
builder.withNumListstatusThreads(12);
Assert.assertEquals(12, builder.build().getNumListstatusThreads());
builder.withNumListstatusThreads(0);
Assert.assertEquals(0, builder.build().getNumListstatusThreads());
// Ignore large number of threads.
builder.withNumListstatusThreads(MAX_NUM_LISTSTATUS_THREADS * 2);
Assert.assertEquals(MAX_NUM_LISTSTATUS_THREADS,
builder.build().getNumListstatusThreads());
}
@Test
public void testSourceListing() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"));
Assert.assertEquals(new Path("hdfs://localhost:8020/source/first"),
builder.build().getSourceFileListing());
}
@Test(expected = IllegalArgumentException.class)
public void testMissingTarget() {
new DistCpOptions.Builder(new Path("hdfs://localhost:8020/source/first"),
null);
}
@Test
public void testToString() {
DistCpOptions option = new DistCpOptions.Builder(new Path("abc"),
new Path("xyz")).build();
String val = "DistCpOptions{atomicCommit=false, syncFolder=false, " +
"deleteMissing=false, ignoreFailures=false, overwrite=false, " +
"append=false, useDiff=false, useRdiff=false, " +
"fromSnapshot=null, toSnapshot=null, " +
"skipCRC=false, blocking=true, numListstatusThreads=0, maxMaps=20, " +
"mapBandwidth=0.0, copyStrategy='uniformsize', preserveStatus=[], " +
"atomicWorkPath=null, logPath=null, sourceFileListing=abc, " +
"sourcePaths=null, targetPath=xyz, filtersFile='null'," +
" blocksPerChunk=0, copyBufferSize=8192, verboseLog=false}";
String optionString = option.toString();
Assert.assertEquals(val, optionString);
Assert.assertNotSame(DistCpOptionSwitch.ATOMIC_COMMIT.toString(),
DistCpOptionSwitch.ATOMIC_COMMIT.name());
}
@Test
public void testCopyStrategy() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"));
Assert.assertEquals(DistCpConstants.UNIFORMSIZE,
builder.build().getCopyStrategy());
builder.withCopyStrategy("dynamic");
Assert.assertEquals("dynamic", builder.build().getCopyStrategy());
}
@Test
public void testTargetPath() {
final DistCpOptions options = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/")).build();
Assert.assertEquals(new Path("hdfs://localhost:8020/target/"),
options.getTargetPath());
}
@Test
public void testPreserve() {
DistCpOptions options = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.build();
Assert.assertFalse(options.shouldPreserve(FileAttribute.BLOCKSIZE));
Assert.assertFalse(options.shouldPreserve(FileAttribute.REPLICATION));
Assert.assertFalse(options.shouldPreserve(FileAttribute.PERMISSION));
Assert.assertFalse(options.shouldPreserve(FileAttribute.USER));
Assert.assertFalse(options.shouldPreserve(FileAttribute.GROUP));
Assert.assertFalse(options.shouldPreserve(FileAttribute.CHECKSUMTYPE));
options = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.preserve(FileAttribute.ACL)
.build();
Assert.assertFalse(options.shouldPreserve(FileAttribute.BLOCKSIZE));
Assert.assertFalse(options.shouldPreserve(FileAttribute.REPLICATION));
Assert.assertFalse(options.shouldPreserve(FileAttribute.PERMISSION));
Assert.assertFalse(options.shouldPreserve(FileAttribute.USER));
Assert.assertFalse(options.shouldPreserve(FileAttribute.GROUP));
Assert.assertFalse(options.shouldPreserve(FileAttribute.CHECKSUMTYPE));
Assert.assertTrue(options.shouldPreserve(FileAttribute.ACL));
options = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.preserve(FileAttribute.BLOCKSIZE)
.preserve(FileAttribute.REPLICATION)
.preserve(FileAttribute.PERMISSION)
.preserve(FileAttribute.USER)
.preserve(FileAttribute.GROUP)
.preserve(FileAttribute.CHECKSUMTYPE)
.build();
Assert.assertTrue(options.shouldPreserve(FileAttribute.BLOCKSIZE));
Assert.assertTrue(options.shouldPreserve(FileAttribute.REPLICATION));
Assert.assertTrue(options.shouldPreserve(FileAttribute.PERMISSION));
Assert.assertTrue(options.shouldPreserve(FileAttribute.USER));
Assert.assertTrue(options.shouldPreserve(FileAttribute.GROUP));
Assert.assertTrue(options.shouldPreserve(FileAttribute.CHECKSUMTYPE));
Assert.assertFalse(options.shouldPreserve(FileAttribute.XATTR));
}
@Test
public void testAppendOption() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withSyncFolder(true)
.withAppend(true);
Assert.assertTrue(builder.build().shouldAppend());
try {
// make sure -append is only valid when -update is specified
new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withAppend(true)
.build();
fail("Append should fail if update option is not specified");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"Append is valid only with update options", e);
}
try {
// make sure -append is invalid when skipCrc is specified
new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"))
.withSyncFolder(true)
.withAppend(true)
.withCRC(true)
.build();
fail("Append should fail if skipCrc option is specified");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"Append is disallowed when skipping CRC", e);
}
}
@Test
public void testDiffOption() {
DistCpOptions options = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withSyncFolder(true)
.withUseDiff("s1", "s2")
.build();
Assert.assertTrue(options.shouldUseDiff());
Assert.assertEquals("s1", options.getFromSnapshot());
Assert.assertEquals("s2", options.getToSnapshot());
options = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withSyncFolder(true)
.withUseDiff("s1", ".")
.build();
Assert.assertTrue(options.shouldUseDiff());
Assert.assertEquals("s1", options.getFromSnapshot());
Assert.assertEquals(".", options.getToSnapshot());
// make sure -diff is only valid when -update is specified
try {
new DistCpOptions.Builder(new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withUseDiff("s1", "s2")
.build();
fail("-diff should fail if -update option is not specified");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"-diff/-rdiff is valid only with -update option", e);
}
try {
new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withSyncFolder(true)
.withUseDiff("s1", "s2")
.withDeleteMissing(true)
.build();
fail("Should fail as -delete and -diff/-rdiff are mutually exclusive.");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"-delete and -diff/-rdiff are mutually exclusive.", e);
}
try {
new DistCpOptions.Builder(new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withUseDiff("s1", "s2")
.withDeleteMissing(true)
.build();
fail("-diff should fail if -update option is not specified");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"-delete and -diff/-rdiff are mutually exclusive.", e);
}
try {
new DistCpOptions.Builder(new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"))
.withDeleteMissing(true)
.withUseDiff("s1", "s2")
.build();
fail("Should have failed as -delete and -diff are mutually exclusive");
} catch (IllegalArgumentException e) {
assertExceptionContains(
"-delete and -diff/-rdiff are mutually exclusive", e);
}
}
@Test
public void testExclusionsOption() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/first"),
new Path("hdfs://localhost:8020/target/"));
Assert.assertNull(builder.build().getFiltersFile());
builder.withFiltersFile("/tmp/filters.txt");
Assert.assertEquals("/tmp/filters.txt", builder.build().getFiltersFile());
}
@Test
public void testSetOptionsForSplitLargeFile() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
new Path("hdfs://localhost:8020/source/"),
new Path("hdfs://localhost:8020/target/"))
.withAppend(true)
.withSyncFolder(true);
Assert.assertFalse(builder.build().shouldPreserve(FileAttribute.BLOCKSIZE));
Assert.assertTrue(builder.build().shouldAppend());
builder.withBlocksPerChunk(5440);
Assert.assertTrue(builder.build().shouldPreserve(FileAttribute.BLOCKSIZE));
Assert.assertFalse(builder.build().shouldAppend());
}
@Test
public void testSetCopyBufferSize() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertEquals(DistCpConstants.COPY_BUFFER_SIZE_DEFAULT,
builder.build().getCopyBufferSize());
builder.withCopyBufferSize(4194304);
Assert.assertEquals(4194304,
builder.build().getCopyBufferSize());
builder.withCopyBufferSize(-1);
Assert.assertEquals(DistCpConstants.COPY_BUFFER_SIZE_DEFAULT,
builder.build().getCopyBufferSize());
}
@Test
public void testVerboseLog() {
final DistCpOptions.Builder builder = new DistCpOptions.Builder(
Collections.singletonList(new Path("hdfs://localhost:8020/source")),
new Path("hdfs://localhost:8020/target/"));
Assert.assertFalse(builder.build().shouldVerboseLog());
try {
builder.withVerboseLog(true).build();
fail("-v should fail if -log option is not specified");
} catch (IllegalArgumentException e) {
assertExceptionContains("-v is valid only with -log option", e);
}
final Path logPath = new Path("hdfs://localhost:8020/logs");
builder.withLogPath(logPath).withVerboseLog(true);
Assert.assertTrue(builder.build().shouldVerboseLog());
}
}