/*
* 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.file.meta;
import alluxio.Constants;
import alluxio.exception.BlockInfoException;
import alluxio.exception.ExceptionMessage;
import alluxio.exception.FileAlreadyCompletedException;
import alluxio.exception.InvalidFileSizeException;
import alluxio.exception.InvalidPathException;
import alluxio.security.authorization.Mode;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.util.ArrayList;
import java.util.List;
/**
* Unit tests for {@link InodeFile}.
*/
public final class InodeFileTest extends AbstractInodeTest {
private static final long LENGTH = 100;
@Rule
public ExpectedException mExpectedException = ExpectedException.none();
/**
* Tests the {@link InodeFile#equals(Object)} method.
*/
@Test
public void equals() {
InodeFile inode1 = createInodeFile(1);
// self equal
Assert.assertEquals(inode1, inode1);
InodeFile inode2 = createInodeFile(1);
// equal with same id
Assert.assertEquals(inode1, inode2);
InodeFile inode3 = createInodeFile(3);
Assert.assertFalse(inode1.equals(inode3));
}
/**
* Tests the {@link InodeFile#getId()} method.
*/
@Test
public void getId() {
InodeFile inode1 = createInodeFile(1);
Assert.assertEquals(createInodeFileId(1), inode1.getId());
}
/**
* Tests the {@link InodeFile#setLength(long)} method.
*/
@Test
public void setLength() {
InodeFile inodeFile = createInodeFile(1);
inodeFile.setLength(LENGTH);
Assert.assertEquals(LENGTH, inodeFile.getLength());
}
/**
* Tests that an exception is thrown when trying to create a file with a negative length.
*/
@Test
public void setNegativeLength() throws Exception {
mThrown.expect(InvalidFileSizeException.class);
mThrown.expectMessage("File testFile1 cannot have negative length: -2");
InodeFile inodeFile = createInodeFile(1);
inodeFile.complete(-2);
}
/**
* Tests a file can be complete with an unknown length.
*/
@Test
public void setUnknownLength() throws Exception {
InodeFile inodeFile = createInodeFile(1);
inodeFile.complete(Constants.UNKNOWN_SIZE);
}
/**
* Tests that an exception is thrown when trying to complete a file twice.
*/
@Test
public void completeTwice() throws Exception {
mThrown.expect(FileAlreadyCompletedException.class);
mThrown.expectMessage("File testFile1 has already been completed.");
InodeFile inodeFile = createInodeFile(1);
inodeFile.complete(LENGTH);
inodeFile.complete(LENGTH);
}
/**
* Tests a file can be completed if its length was unknown previously.
*/
@Test
public void completeUnknown() throws Exception {
InodeFile inodeFile = createInodeFile(1);
inodeFile.complete(Constants.UNKNOWN_SIZE);
inodeFile.complete(LENGTH);
}
/**
* Tests the {@link InodeFile#getBlockSizeBytes()} method.
*/
@Test
public void getBlockSizeBytes() {
InodeFile inode1 = createInodeFile(1);
Assert.assertEquals(Constants.KB, inode1.getBlockSizeBytes());
}
/**
* Tests the {@link InodeFile#getBlockIdByIndex(int)} method.
*/
@Test
public void getBlockIdByIndex() throws Exception {
InodeFile inodeFile = createInodeFile(1);
List<Long> blockIds = new ArrayList<>();
final int NUM_BLOCKS = 3;
for (int i = 0; i < NUM_BLOCKS; i++) {
blockIds.add(inodeFile.getNewBlockId());
}
for (int i = 0; i < NUM_BLOCKS; i++) {
Assert.assertEquals(blockIds.get(i), (Long) inodeFile.getBlockIdByIndex(i));
}
try {
inodeFile.getBlockIdByIndex(-1);
Assert.fail();
} catch (BlockInfoException e) {
Assert.assertEquals(String.format("blockIndex -1 is out of range. File blocks: %d",
NUM_BLOCKS), e.getMessage());
}
try {
inodeFile.getBlockIdByIndex(NUM_BLOCKS);
Assert.fail();
} catch (BlockInfoException e) {
Assert.assertEquals(String.format("blockIndex %d is out of range. File blocks: %d",
NUM_BLOCKS, NUM_BLOCKS), e.getMessage());
}
}
/**
* Tests the {@link InodeFile#setCompleted(boolean)} method.
*/
@Test
public void setCompleted() {
InodeFile inode1 = createInodeFile(1);
Assert.assertFalse(inode1.isCompleted());
inode1.setCompleted(true);
Assert.assertTrue(inode1.isCompleted());
}
/**
* Tests the {@link InodeFile#getMode()} method.
*/
@Test
public void permissionStatus() {
InodeFile inode1 = createInodeFile(1);
Assert.assertEquals(TEST_OWNER, inode1.getOwner());
Assert.assertEquals(TEST_GROUP, inode1.getGroup());
Assert.assertEquals(Mode.defaults().applyFileUMask().toShort(), inode1.getMode());
}
/**
* Tests the {@link Inode#lockRead()} and {@link Inode#unlockRead()} methods.
*/
@Test
public void lockRead() {
InodeFile inode1 = createInodeFile(1);
Assert.assertFalse(inode1.isReadLocked());
Assert.assertFalse(inode1.isWriteLocked());
inode1.lockRead();
Assert.assertTrue(inode1.isReadLocked());
Assert.assertFalse(inode1.isWriteLocked());
inode1.unlockRead();
Assert.assertFalse(inode1.isReadLocked());
Assert.assertFalse(inode1.isWriteLocked());
}
/**
* Tests the {@link Inode#lockReadAndCheckParent(Inode)} method.
*/
@Test
public void lockReadAndCheckParent() throws Exception {
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setParentId(dir1.getId());
inode1.lockReadAndCheckParent(dir1);
Assert.assertTrue(inode1.isReadLocked());
inode1.unlockRead();
}
/**
* Tests the {@link Inode#lockReadAndCheckParent(Inode)} method fails when the parent is
* not consistent.
*/
@Test
public void lockReadAndCheckParentInvalid() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setParentId(dir1.getId() - 1);
inode1.lockReadAndCheckParent(dir1);
}
/**
* Tests the {@link Inode#lockReadAndCheckNameAndParent(Inode, String)} method.
*/
@Test
public void lockReadAndCheckNameAndParent() throws Exception {
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId());
inode1.lockReadAndCheckNameAndParent(dir1, name);
Assert.assertTrue(inode1.isReadLocked());
inode1.unlockRead();
}
/**
* Tests the {@link Inode#lockReadAndCheckNameAndParent(Inode, String)} method fails when the
* parent and name are not consistent.
*/
@Test
public void lockReadAndCheckNameAndParentInvalid() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId() - 1);
inode1.lockReadAndCheckNameAndParent(dir1, "invalid");
}
/**
* Tests the {@link Inode#lockReadAndCheckNameAndParent(Inode, String)} method fails when the name
* is not consistent.
*/
@Test
public void lockReadAndCheckNameAndParentInvalidName() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId());
inode1.lockReadAndCheckNameAndParent(dir1, "invalid");
}
/**
* Tests the {@link Inode#lockReadAndCheckNameAndParent(Inode, String)} method fails when the
* parent is not consistent.
*/
@Test
public void lockReadAndCheckNameAndParentInvalidParent() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId() - 1);
inode1.lockReadAndCheckNameAndParent(dir1, name);
}
/**
* Tests the {@link Inode#lockWrite()} and {@link Inode#unlockWrite()} methods.
*/
@Test
public void lockWrite() {
InodeFile inode1 = createInodeFile(1);
inode1.lockWrite();
Assert.assertFalse(inode1.isReadLocked());
Assert.assertTrue(inode1.isWriteLocked());
inode1.unlockWrite();
Assert.assertFalse(inode1.isReadLocked());
Assert.assertFalse(inode1.isWriteLocked());
}
/**
* Tests the {@link Inode#lockWriteAndCheckParent(Inode)} method.
*/
@Test
public void lockWriteAndCheckParent() throws Exception {
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setParentId(dir1.getId());
inode1.lockWriteAndCheckParent(dir1);
Assert.assertTrue(inode1.isWriteLocked());
inode1.unlockWrite();
}
/**
* Tests the {@link Inode#lockWriteAndCheckParent(Inode)} method fails when the parent is
* not consistent.
*/
@Test
public void lockWriteAndCheckParentInvalid() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setParentId(dir1.getId() - 1);
inode1.lockWriteAndCheckParent(dir1);
}
/**
* Tests the {@link Inode#lockWriteAndCheckNameAndParent(Inode, String)} method.
*/
@Test
public void lockWriteAndCheckNameAndParent() throws Exception {
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId());
inode1.lockWriteAndCheckNameAndParent(dir1, name);
Assert.assertTrue(inode1.isWriteLocked());
inode1.unlockWrite();
}
/**
* Tests the {@link Inode#lockWriteAndCheckNameAndParent(Inode, String)} method fails when the
* parent and name are not consistent.
*/
@Test
public void lockWriteAndCheckNameAndParentInvalid() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId() - 1);
inode1.lockWriteAndCheckNameAndParent(dir1, "invalid");
}
/**
* Tests the {@link Inode#lockWriteAndCheckNameAndParent(Inode, String)} method fails when the
* name is not consistent.
*/
@Test
public void lockWriteAndCheckNameAndParentInvalidName() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId());
inode1.lockWriteAndCheckNameAndParent(dir1, "invalid");
}
/**
* Tests the {@link Inode#lockWriteAndCheckNameAndParent(Inode, String)} method fails when the
* parent is not consistent.
*/
@Test
public void lockWriteAndCheckNameAndParentInvalidParent() throws Exception {
mExpectedException.expect(InvalidPathException.class);
mExpectedException.expectMessage(ExceptionMessage.PATH_INVALID_CONCURRENT_RENAME.getMessage());
String name = "file";
InodeFile inode1 = createInodeFile(1);
InodeDirectory dir1 = createInodeDirectory();
inode1.setName(name);
inode1.setParentId(dir1.getId() - 1);
inode1.lockWriteAndCheckNameAndParent(dir1, name);
}
}