/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.master.lineage;
import alluxio.AlluxioURI;
import alluxio.exception.ExceptionMessage;
import alluxio.exception.FileDoesNotExistException;
import alluxio.exception.LineageDeletionException;
import alluxio.exception.LineageDoesNotExistException;
import alluxio.job.CommandLineJob;
import alluxio.job.Job;
import alluxio.job.JobConf;
import alluxio.master.MasterRegistry;
import alluxio.master.file.FileSystemMaster;
import alluxio.master.file.options.CompleteFileOptions;
import alluxio.master.journal.Journal;
import alluxio.master.journal.JournalFactory;
import alluxio.util.IdUtils;
import alluxio.util.ThreadFactoryUtils;
import alluxio.util.executor.ExecutorServiceFactories;
import alluxio.wire.FileInfo;
import alluxio.wire.LineageInfo;
import alluxio.wire.TtlAction;
import com.google.common.collect.Lists;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* Unit tests for {@link LineageMaster}.
*/
public final class LineageMasterTest {
private ExecutorService mExecutorService;
private LineageMaster mLineageMaster;
private FileSystemMaster mFileSystemMaster;
private Job mJob;
private MasterRegistry mRegistry;
/** Rule to create a new temporary folder during each test. */
@Rule
public TemporaryFolder mTestFolder = new TemporaryFolder();
/**
* Sets up all dependencies before a test runs.
*/
@Before
public void before() throws Exception {
mRegistry = new MasterRegistry();
JournalFactory factory =
new Journal.Factory(new URI(mTestFolder.newFolder().getAbsolutePath()));
mFileSystemMaster = Mockito.mock(FileSystemMaster.class);
mRegistry.add(FileSystemMaster.class, mFileSystemMaster);
ThreadFactory threadPool = ThreadFactoryUtils.build("LineageMasterTest-%d", true);
mExecutorService = Executors.newFixedThreadPool(2, threadPool);
mLineageMaster = new LineageMaster(mFileSystemMaster, factory,
ExecutorServiceFactories.constantExecutorServiceFactory(mExecutorService));
mRegistry.add(LineageMaster.class, mLineageMaster);
mJob = new CommandLineJob("test", new JobConf("output"));
}
@After
public void after() throws Exception {
mRegistry.stop();
}
/**
* Tests the {@link LineageMaster#getLineageInfoList()} method.
*/
@Test
public void listLineages() throws Exception {
Mockito.when(mFileSystemMaster.getPath(Mockito.anyLong())).thenReturn(new AlluxioURI("test"));
mRegistry.start(true);
mLineageMaster.createLineage(new ArrayList<AlluxioURI>(),
Lists.newArrayList(new AlluxioURI("/test1")), mJob);
mLineageMaster.createLineage(Lists.newArrayList(new AlluxioURI("/test1")),
Lists.newArrayList(new AlluxioURI("/test2")), mJob);
List<LineageInfo> info = mLineageMaster.getLineageInfoList();
Assert.assertEquals(2, info.size());
}
/**
* Tests that an exception is thrown when trying to create a lineage for a non-existing file via
* the {@link LineageMaster#createLineage(List, List, Job)} method.
*/
@Test
public void createLineageWithNonExistingFile() throws Exception {
AlluxioURI missingInput = new AlluxioURI("/test1");
Mockito.when(mFileSystemMaster.getFileId(missingInput)).thenReturn(IdUtils.INVALID_FILE_ID);
mRegistry.start(true);
// try catch block used because ExpectedExceptionRule conflicts with Powermock
try {
mLineageMaster.createLineage(Lists.newArrayList(missingInput),
Lists.newArrayList(new AlluxioURI("/test2")), mJob);
Assert.fail();
} catch (FileDoesNotExistException e) {
Assert.assertEquals(ExceptionMessage.LINEAGE_INPUT_FILE_NOT_EXIST.getMessage("/test1"),
e.getMessage());
}
}
/**
* Tests the {@link LineageMaster#deleteLineage(long, boolean)} method.
*/
@Test
public void deleteLineage() throws Exception {
mRegistry.start(true);
long l1 = mLineageMaster.createLineage(new ArrayList<AlluxioURI>(),
Lists.newArrayList(new AlluxioURI("/test1")), mJob);
mLineageMaster.createLineage(Lists.newArrayList(new AlluxioURI("/test1")),
Lists.newArrayList(new AlluxioURI("/test2")), mJob);
mLineageMaster.deleteLineage(l1, true);
List<LineageInfo> info = mLineageMaster.getLineageInfoList();
Assert.assertEquals(0, info.size());
}
/**
* Tests that an exception is thrown when trying to delete a non-existing lineage via the
* {@link LineageMaster#deleteLineage(long, boolean)} method.
*/
@Test
public void deleteNonexistingLineage() throws Exception {
mRegistry.start(true);
long id = 1L;
try {
mLineageMaster.deleteLineage(id, false);
Assert.fail();
} catch (LineageDoesNotExistException e) {
Assert.assertEquals(ExceptionMessage.LINEAGE_DOES_NOT_EXIST.getMessage(id), e.getMessage());
}
}
/**
* Tests that an exception is thrown when trying to delete a lineage with children via the
* {@link LineageMaster#deleteLineage(long, boolean)} without setting the {@code cascade} flag to
* {@code true}.
*/
@Test
public void deleteLineageWithChildren() throws Exception {
mRegistry.start(true);
long l1 = mLineageMaster.createLineage(new ArrayList<AlluxioURI>(),
Lists.newArrayList(new AlluxioURI("/test1")), mJob);
mLineageMaster.createLineage(Lists.newArrayList(new AlluxioURI("/test1")),
Lists.newArrayList(new AlluxioURI("/test2")), mJob);
try {
mLineageMaster.deleteLineage(l1, false);
Assert.fail();
} catch (LineageDeletionException e) {
Assert.assertEquals(ExceptionMessage.DELETE_LINEAGE_WITH_CHILDREN.getMessage(l1),
e.getMessage());
}
}
/**
* Tests the {@link LineageMaster#reinitializeFile(String, long, long, TtlAction)} method.
*/
@Test
public void reinitializeFile() throws Exception {
FileInfo fileInfo = new FileInfo();
fileInfo.setCompleted(false);
Mockito.when(mFileSystemMaster.getFileInfo(Mockito.any(Long.class))).thenReturn(fileInfo);
mRegistry.start(true);
mLineageMaster.createLineage(new ArrayList<AlluxioURI>(),
Lists.newArrayList(new AlluxioURI("/test1")), mJob);
mLineageMaster.reinitializeFile("/test1", 500L, 10L, TtlAction.DELETE);
Mockito.verify(mFileSystemMaster).reinitializeFile(new AlluxioURI("/test1"), 500L, 10L,
TtlAction.DELETE);
}
/**
* Tests that completing a file asynchronously works.
*/
@Test
public void asyncCompleteFile() throws Exception {
mRegistry.start(true);
AlluxioURI file = new AlluxioURI("/test1");
mLineageMaster.createLineage(new ArrayList<AlluxioURI>(), Lists.newArrayList(file), mJob);
mFileSystemMaster.completeFile(file, CompleteFileOptions.defaults());
Mockito.verify(mFileSystemMaster).completeFile(Mockito.eq(file),
Mockito.any(CompleteFileOptions.class));
}
@Test
public void stop() throws Exception {
mRegistry.start(true);
mRegistry.stop();
Assert.assertTrue(mExecutorService.isShutdown());
Assert.assertTrue(mExecutorService.isTerminated());
}
}