/* * 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.AlluxioURI; import alluxio.Configuration; import alluxio.ConfigurationTestUtils; import alluxio.Constants; import alluxio.PropertyKey; import alluxio.exception.BlockInfoException; import alluxio.exception.ExceptionMessage; import alluxio.exception.FileAlreadyExistsException; import alluxio.exception.FileDoesNotExistException; import alluxio.exception.InvalidPathException; import alluxio.master.MasterRegistry; import alluxio.master.block.BlockMaster; import alluxio.master.block.BlockMasterFactory; import alluxio.master.file.options.CreateDirectoryOptions; import alluxio.master.file.options.CreateFileOptions; import alluxio.master.file.options.CreatePathOptions; import alluxio.master.file.options.DeleteOptions; import alluxio.master.journal.Journal; import alluxio.master.journal.JournalFactory; import alluxio.master.journal.NoopJournalContext; import alluxio.security.authorization.Mode; import alluxio.underfs.UfsManager; import alluxio.util.CommonUtils; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; import org.mockito.Mockito; import java.io.IOException; import java.net.URI; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Unit tests for {@link InodeTree}. */ public final class InodeTreeTest { private static final String TEST_PATH = "test"; private static final AlluxioURI TEST_URI = new AlluxioURI("/test"); private static final AlluxioURI NESTED_URI = new AlluxioURI("/nested/test"); private static final AlluxioURI NESTED_FILE_URI = new AlluxioURI("/nested/test/file"); public static final String TEST_OWNER = "user1"; public static final String TEST_GROUP = "group1"; public static final Mode TEST_DIR_MODE = new Mode((short) 0755); public static final Mode TEST_FILE_MODE = new Mode((short) 0644); private static CreateFileOptions sFileOptions; private static CreateDirectoryOptions sDirectoryOptions; private static CreateFileOptions sNestedFileOptions; private static CreateDirectoryOptions sNestedDirectoryOptions; private InodeTree mTree; private MasterRegistry mRegistry; /** Rule to create a new temporary folder during each test. */ @Rule public TemporaryFolder mTestFolder = new TemporaryFolder(); /** The exception expected to be thrown. */ @Rule public ExpectedException mThrown = ExpectedException.none(); /** * 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())); BlockMaster blockMaster = new BlockMasterFactory().create(mRegistry, factory); InodeDirectoryIdGenerator directoryIdGenerator = new InodeDirectoryIdGenerator(blockMaster); UfsManager ufsManager = Mockito.mock(UfsManager.class); MountTable mountTable = new MountTable(ufsManager); mTree = new InodeTree(blockMaster, directoryIdGenerator, mountTable); mRegistry.start(true); Configuration.set(PropertyKey.SECURITY_AUTHORIZATION_PERMISSION_ENABLED, "true"); Configuration.set(PropertyKey.SECURITY_AUTHORIZATION_PERMISSION_SUPERGROUP, "test-supergroup"); mTree.initializeRoot(TEST_OWNER, TEST_GROUP, TEST_DIR_MODE); } @After public void after() throws Exception { mRegistry.stop(); ConfigurationTestUtils.resetConfiguration(); } /** * Sets up dependencies before a single test runs. */ @BeforeClass public static void beforeClass() throws Exception { sFileOptions = CreateFileOptions.defaults().setBlockSizeBytes(Constants.KB).setOwner(TEST_OWNER) .setGroup(TEST_GROUP).setMode(TEST_FILE_MODE); sDirectoryOptions = CreateDirectoryOptions.defaults().setOwner(TEST_OWNER).setGroup(TEST_GROUP) .setMode(TEST_DIR_MODE); sNestedFileOptions = CreateFileOptions.defaults().setBlockSizeBytes(Constants.KB) .setOwner(TEST_OWNER).setGroup(TEST_GROUP) .setMode(TEST_FILE_MODE).setRecursive(true); sNestedDirectoryOptions = CreateDirectoryOptions.defaults().setOwner(TEST_OWNER).setGroup(TEST_GROUP) .setMode(TEST_DIR_MODE).setRecursive(true); } /** * Tests that initializing the root twice results in the same root. */ @Test public void initializeRootTwice() throws Exception { Inode<?> root = getInodeByPath(mTree, new AlluxioURI("/")); // initializeRoot call does nothing mTree.initializeRoot(TEST_OWNER, TEST_GROUP, TEST_DIR_MODE); Assert.assertEquals(TEST_OWNER, root.getOwner()); Inode<?> newRoot = getInodeByPath(mTree, new AlluxioURI("/")); Assert.assertEquals(root, newRoot); } /** * Tests the {@link InodeTree#createPath(LockedInodePath, CreatePathOptions)} method for creating * directories. */ @Test public void createDirectory() throws Exception { // create directory createPath(mTree, TEST_URI, sDirectoryOptions); Assert.assertTrue(mTree.inodePathExists(TEST_URI)); Inode<?> test = getInodeByPath(mTree, TEST_URI); Assert.assertEquals(TEST_PATH, test.getName()); Assert.assertTrue(test.isDirectory()); Assert.assertEquals("user1", test.getOwner()); Assert.assertEquals("group1", test.getGroup()); Assert.assertEquals(TEST_DIR_MODE.toShort(), test.getMode()); // create nested directory createPath(mTree, NESTED_URI, sNestedDirectoryOptions); Assert.assertTrue(mTree.inodePathExists(NESTED_URI)); Inode<?> nested = getInodeByPath(mTree, NESTED_URI); Assert.assertEquals(TEST_PATH, nested.getName()); Assert.assertEquals(2, nested.getParentId()); Assert.assertTrue(test.isDirectory()); Assert.assertEquals("user1", test.getOwner()); Assert.assertEquals("group1", test.getGroup()); Assert.assertEquals(TEST_DIR_MODE.toShort(), test.getMode()); } /** * Tests that an exception is thrown when trying to create an already existing directory with the * {@code allowExists} flag set to {@code false}. */ @Test public void createExistingDirectory() throws Exception { // create directory createPath(mTree, TEST_URI, sDirectoryOptions); // create again with allowExists true createPath(mTree, TEST_URI, CreateDirectoryOptions.defaults().setAllowExists(true)); // create again with allowExists false mThrown.expect(FileAlreadyExistsException.class); mThrown.expectMessage(ExceptionMessage.FILE_ALREADY_EXISTS.getMessage(TEST_URI)); createPath(mTree, TEST_URI, CreateDirectoryOptions.defaults().setAllowExists(false)); } /** * Tests that creating a file under a pinned directory works. */ @Test public void createFileUnderPinnedDirectory() throws Exception { // create nested directory createPath(mTree, NESTED_URI, sNestedDirectoryOptions); // pin nested folder try ( LockedInodePath inodePath = mTree.lockFullInodePath(NESTED_URI, InodeTree.LockMode.WRITE)) { mTree.setPinned(inodePath, true); } // create nested file under pinned folder createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); // the nested file is pinned Assert.assertEquals(1, mTree.getPinIdSet().size()); } /** * Tests the {@link InodeTree#createPath(LockedInodePath, CreatePathOptions)} method for * creating a file. */ @Test public void createFile() throws Exception { // created nested file createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); Inode<?> nestedFile = getInodeByPath(mTree, NESTED_FILE_URI); Assert.assertEquals("file", nestedFile.getName()); Assert.assertEquals(2, nestedFile.getParentId()); Assert.assertTrue(nestedFile.isFile()); Assert.assertEquals("user1", nestedFile.getOwner()); Assert.assertEquals("group1", nestedFile.getGroup()); Assert.assertEquals(TEST_FILE_MODE.toShort(), nestedFile.getMode()); } /** * Tests the {@link InodeTree#createPath(LockedInodePath, CreatePathOptions)} method. */ @Test public void createPathTest() throws Exception { // save the last mod time of the root long lastModTime = mTree.getRoot().getLastModificationTimeMs(); // sleep to ensure a different last modification time CommonUtils.sleepMs(10); // Need to use updated options to set the correct last mod time. CreateDirectoryOptions dirOptions = CreateDirectoryOptions.defaults().setOwner(TEST_OWNER).setGroup(TEST_GROUP) .setMode(TEST_DIR_MODE).setRecursive(true); // create nested directory InodeTree.CreatePathResult createResult = createPath(mTree, NESTED_URI, dirOptions); List<Inode<?>> modified = createResult.getModified(); List<Inode<?>> created = createResult.getCreated(); // 1 modified directory Assert.assertEquals(1, modified.size()); Assert.assertEquals("", modified.get(0).getName()); Assert.assertNotEquals(lastModTime, modified.get(0).getLastModificationTimeMs()); // 2 created directories Assert.assertEquals(2, created.size()); Assert.assertEquals("nested", created.get(0).getName()); Assert.assertEquals("test", created.get(1).getName()); // save the last mod time of 'test' lastModTime = created.get(1).getLastModificationTimeMs(); // sleep to ensure a different last modification time CommonUtils.sleepMs(10); // creating the directory path again results in no new inodes. try { createPath(mTree, NESTED_URI, dirOptions); Assert.assertTrue("createPath should throw FileAlreadyExistsException", false); } catch (FileAlreadyExistsException e) { Assert.assertEquals(e.getMessage(), ExceptionMessage.FILE_ALREADY_EXISTS.getMessage(NESTED_URI)); } // create a file CreateFileOptions options = CreateFileOptions.defaults().setBlockSizeBytes(Constants.KB).setRecursive(true); createResult = createPath(mTree, NESTED_FILE_URI, options); modified = createResult.getModified(); created = createResult.getCreated(); // test directory was modified Assert.assertEquals(1, modified.size()); Assert.assertEquals("test", modified.get(0).getName()); Assert.assertNotEquals(lastModTime, modified.get(0).getLastModificationTimeMs()); // file was created Assert.assertEquals(1, created.size()); Assert.assertEquals("file", created.get(0).getName()); } /** * Tests that an exception is thrown when trying to create the root path twice. */ @Test public void createRootPath() throws Exception { mThrown.expect(FileAlreadyExistsException.class); mThrown.expectMessage("/"); createPath(mTree, new AlluxioURI("/"), sFileOptions); } /** * Tests that an exception is thrown when trying to create a file with invalid block size. */ @Test public void createFileWithInvalidBlockSize() throws Exception { mThrown.expect(BlockInfoException.class); mThrown.expectMessage("Invalid block size 0"); CreateFileOptions options = CreateFileOptions.defaults().setBlockSizeBytes(0); createPath(mTree, TEST_URI, options); } /** * Tests that an exception is thrown when trying to create a file with a negative block size. */ @Test public void createFileWithNegativeBlockSize() throws Exception { mThrown.expect(BlockInfoException.class); mThrown.expectMessage("Invalid block size -1"); CreateFileOptions options = CreateFileOptions.defaults().setBlockSizeBytes(-1); createPath(mTree, TEST_URI, options); } /** * Tests that an exception is thrown when trying to create a file under a non-existing directory. */ @Test public void createFileUnderNonexistingDir() throws Exception { mThrown.expect(FileDoesNotExistException.class); mThrown.expectMessage("File /nested/test creation failed. Component 1(nested) does not exist"); createPath(mTree, NESTED_URI, sFileOptions); } /** * Tests that an exception is thrown when trying to create a file twice. */ @Test public void createFileTwice() throws Exception { mThrown.expect(FileAlreadyExistsException.class); mThrown.expectMessage("/nested/test"); createPath(mTree, NESTED_URI, sNestedFileOptions); createPath(mTree, NESTED_URI, sNestedFileOptions); } /** * Tests that an exception is thrown when trying to create a file under a file path. */ @Test public void createFileUnderFile() throws Exception { mThrown.expect(InvalidPathException.class); mThrown.expectMessage("Traversal failed. Component 2(test) is a file"); createPath(mTree, NESTED_URI, sNestedFileOptions); createPath(mTree, new AlluxioURI("/nested/test/test"), sNestedFileOptions); } /** * Tests {@link InodeTree#inodeIdExists(long)}. */ @Test public void inodeIdExists() throws Exception { Assert.assertTrue(mTree.inodeIdExists(0)); Assert.assertFalse(mTree.inodeIdExists(1)); createPath(mTree, TEST_URI, sFileOptions); Inode<?> inode = getInodeByPath(mTree, TEST_URI); Assert.assertTrue(mTree.inodeIdExists(inode.getId())); deleteInodeByPath(mTree, TEST_URI); Assert.assertFalse(mTree.inodeIdExists(inode.getId())); } /** * Tests {@link InodeTree#inodePathExists(AlluxioURI)}. */ @Test public void inodePathExists() throws Exception { Assert.assertFalse(mTree.inodePathExists(TEST_URI)); createPath(mTree, TEST_URI, sFileOptions); Assert.assertTrue(mTree.inodePathExists(TEST_URI)); deleteInodeByPath(mTree, TEST_URI); Assert.assertFalse(mTree.inodePathExists(TEST_URI)); } /** * Tests that an exception is thrown when trying to get an Inode by a non-existing path. */ @Test public void getInodeByNonexistingPath() throws Exception { mThrown.expect(FileDoesNotExistException.class); mThrown.expectMessage("Path /test does not exist"); Assert.assertFalse(mTree.inodePathExists(TEST_URI)); getInodeByPath(mTree, TEST_URI); } /** * Tests that an exception is thrown when trying to get an Inode by a non-existing, nested path. */ @Test public void getInodeByNonexistingNestedPath() throws Exception { mThrown.expect(FileDoesNotExistException.class); mThrown.expectMessage("Path /nested/test/file does not exist"); createPath(mTree, NESTED_URI, sNestedDirectoryOptions); Assert.assertFalse(mTree.inodePathExists(NESTED_FILE_URI)); getInodeByPath(mTree, NESTED_FILE_URI); } /** * Tests that an exception is thrown when trying to get an Inode with an invalid id. */ @Test public void getInodeByInvalidId() throws Exception { mThrown.expect(FileDoesNotExistException.class); mThrown.expectMessage(ExceptionMessage.INODE_DOES_NOT_EXIST.getMessage(1)); Assert.assertFalse(mTree.inodeIdExists(1)); try (LockedInodePath inodePath = mTree.lockFullInodePath(1, InodeTree.LockMode.READ)) { // inode exists } } /** * Tests the {@link InodeTree#isRootId(long)} method. */ @Test public void isRootId() { Assert.assertTrue(mTree.isRootId(0)); Assert.assertFalse(mTree.isRootId(1)); } /** * Tests the {@link InodeTree#getPath(Inode)} method. */ @Test public void getPath() throws Exception { try (LockedInodePath inodePath = mTree.lockFullInodePath(0, InodeTree.LockMode.READ)) { Inode<?> root = inodePath.getInode(); // test root path Assert.assertEquals(new AlluxioURI("/"), mTree.getPath(root)); } // test one level createPath(mTree, TEST_URI, sDirectoryOptions); try (LockedInodePath inodePath = mTree.lockFullInodePath(TEST_URI, InodeTree.LockMode.READ)) { Assert.assertEquals(new AlluxioURI("/test"), mTree.getPath(inodePath.getInode())); } // test nesting createPath(mTree, NESTED_URI, sNestedDirectoryOptions); try (LockedInodePath inodePath = mTree.lockFullInodePath(NESTED_URI, InodeTree.LockMode.READ)) { Assert.assertEquals(new AlluxioURI("/nested/test"), mTree.getPath(inodePath.getInode())); } } /** * Tests the {@link InodeTree#lockDescendants(LockedInodePath, InodeTree.LockMode)} method. */ @Test public void getInodeChildrenRecursive() throws Exception { createPath(mTree, TEST_URI, sDirectoryOptions); createPath(mTree, NESTED_URI, sNestedDirectoryOptions); // add nested file createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); // all inodes under root try (LockedInodePath inodePath = mTree.lockFullInodePath(0, InodeTree.LockMode.READ); InodeLockList lockList = mTree .lockDescendants(inodePath, InodeTree.LockMode.READ)) { List<Inode<?>> inodes = lockList.getInodes(); // /test, /nested, /nested/test, /nested/test/file Assert.assertEquals(4, inodes.size()); } } /** * Tests deleting a nested inode. */ @Test public void deleteInode() throws Exception { createPath(mTree, NESTED_URI, sNestedDirectoryOptions); // all inodes under root try (LockedInodePath inodePath = mTree.lockFullInodePath(0, InodeTree.LockMode.WRITE)) { try (InodeLockList lockList = mTree.lockDescendants(inodePath, InodeTree.LockMode.WRITE)) { List<Inode<?>> inodes = lockList.getInodes(); // /nested, /nested/test Assert.assertEquals(2, inodes.size()); } // delete the nested inode deleteInodeByPath(mTree, NESTED_URI); try (InodeLockList lockList = mTree.lockDescendants(inodePath, InodeTree.LockMode.WRITE)) { List<Inode<?>> inodes = lockList.getInodes(); // only /nested left Assert.assertEquals(1, inodes.size()); } } } /** * Tests the {@link InodeTree#setPinned(LockedInodePath, boolean)} method. */ @Test public void setPinned() throws Exception { createPath(mTree, NESTED_URI, sNestedDirectoryOptions); createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); // no inodes pinned Assert.assertEquals(0, mTree.getPinIdSet().size()); // pin nested folder try ( LockedInodePath inodePath = mTree.lockFullInodePath(NESTED_URI, InodeTree.LockMode.WRITE)) { mTree.setPinned(inodePath, true); } // nested file pinned Assert.assertEquals(1, mTree.getPinIdSet().size()); // unpin nested folder try ( LockedInodePath inodePath = mTree.lockFullInodePath(NESTED_URI, InodeTree.LockMode.WRITE)) { mTree.setPinned(inodePath, false); } Assert.assertEquals(0, mTree.getPinIdSet().size()); } /** * Tests that streaming to a journal checkpoint works. */ @Test public void streamToJournalCheckpoint() throws Exception { InodeDirectory root = mTree.getRoot(); // test root verifyJournal(mTree, Lists.<Inode<?>>newArrayList(root)); // test nested URI createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); InodeDirectory nested = (InodeDirectory) root.getChild("nested"); InodeDirectory test = (InodeDirectory) nested.getChild("test"); Inode<?> file = test.getChild("file"); verifyJournal(mTree, Arrays.asList(root, nested, test, file)); // add a sibling of test and verify journaling is in correct order (breadth first) createPath(mTree, new AlluxioURI("/nested/test1/file1"), sNestedFileOptions); InodeDirectory test1 = (InodeDirectory) nested.getChild("test1"); Inode<?> file1 = test1.getChild("file1"); verifyJournal(mTree, Arrays.asList(root, nested, test, test1, file, file1)); } /** * Tests the {@link InodeTree#addInodeFileFromJournal} and * {@link InodeTree#addInodeDirectoryFromJournal} methods. */ @Test public void addInodeFromJournal() throws Exception { createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); createPath(mTree, new AlluxioURI("/nested/test1/file1"), sNestedFileOptions); InodeDirectory root = mTree.getRoot(); InodeDirectory nested = (InodeDirectory) root.getChild("nested"); InodeDirectory test = (InodeDirectory) nested.getChild("test"); Inode<?> file = test.getChild("file"); InodeDirectory test1 = (InodeDirectory) nested.getChild("test1"); Inode<?> file1 = test1.getChild("file1"); // reset the tree mTree.addInodeDirectoryFromJournal(root.toJournalEntry().getInodeDirectory()); // re-init the root since the tree was reset above mTree.getRoot(); try ( LockedInodePath inodePath = mTree .lockFullInodePath(new AlluxioURI("/"), InodeTree.LockMode.READ)) { try (InodeLockList lockList = mTree .lockDescendants(inodePath, InodeTree.LockMode.READ)) { Assert.assertEquals(0, lockList.getInodes().size()); } mTree.addInodeDirectoryFromJournal(nested.toJournalEntry().getInodeDirectory()); verifyChildrenNames(mTree, inodePath, Sets.newHashSet("nested")); mTree.addInodeDirectoryFromJournal(test.toJournalEntry().getInodeDirectory()); verifyChildrenNames(mTree, inodePath, Sets.newHashSet("nested", "test")); mTree.addInodeDirectoryFromJournal(test1.toJournalEntry().getInodeDirectory()); verifyChildrenNames(mTree, inodePath, Sets.newHashSet("nested", "test", "test1")); mTree.addInodeFileFromJournal(file.toJournalEntry().getInodeFile()); verifyChildrenNames(mTree, inodePath, Sets.newHashSet("nested", "test", "test1", "file")); mTree.addInodeFileFromJournal(file1.toJournalEntry().getInodeFile()); verifyChildrenNames(mTree, inodePath, Sets.newHashSet("nested", "test", "test1", "file", "file1")); } } @Test public void getInodePathById() throws Exception { try (LockedInodePath rootPath = mTree.lockFullInodePath(0, InodeTree.LockMode.READ)) { Assert.assertEquals(0, rootPath.getInode().getId()); } InodeTree.CreatePathResult createResult = createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); for (Inode<?> inode : createResult.getCreated()) { long id = inode.getId(); try (LockedInodePath inodePath = mTree.lockFullInodePath(id, InodeTree.LockMode.READ)) { Assert.assertEquals(id, inodePath.getInode().getId()); } } } @Test public void getInodePathByPath() throws Exception { try (LockedInodePath rootPath = mTree .lockFullInodePath(new AlluxioURI("/"), InodeTree.LockMode.READ)) { Assert.assertTrue(mTree.isRootId(rootPath.getInode().getId())); } // Create a nested file. createPath(mTree, NESTED_FILE_URI, sNestedFileOptions); AlluxioURI uri = new AlluxioURI("/nested"); try (LockedInodePath inodePath = mTree.lockFullInodePath(uri, InodeTree.LockMode.READ)) { Assert.assertEquals(uri.getName(), inodePath.getInode().getName()); } uri = NESTED_URI; try (LockedInodePath inodePath = mTree.lockFullInodePath(uri, InodeTree.LockMode.READ)) { Assert.assertEquals(uri.getName(), inodePath.getInode().getName()); } uri = NESTED_FILE_URI; try (LockedInodePath inodePath = mTree.lockFullInodePath(uri, InodeTree.LockMode.READ)) { Assert.assertEquals(uri.getName(), inodePath.getInode().getName()); } } // Helper to create a path. InodeTree.CreatePathResult createPath(InodeTree root, AlluxioURI path, CreatePathOptions<?> options) throws FileAlreadyExistsException, BlockInfoException, InvalidPathException, IOException, FileDoesNotExistException { try (LockedInodePath inodePath = root.lockInodePath(path, InodeTree.LockMode.WRITE)) { return root.createPath(inodePath, options, new NoopJournalContext()); } } // Helper to get an inode by path. The inode is unlocked before returning. private static Inode<?> getInodeByPath(InodeTree root, AlluxioURI path) throws Exception { try (LockedInodePath inodePath = root.lockFullInodePath(path, InodeTree.LockMode.READ)) { return inodePath.getInode(); } } // Helper to delete an inode by path. private static void deleteInodeByPath(InodeTree root, AlluxioURI path) throws Exception { try (LockedInodePath inodePath = root.lockFullInodePath(path, InodeTree.LockMode.WRITE)) { root.deleteInode(inodePath, System.currentTimeMillis(), DeleteOptions.defaults(), NoopJournalContext.INSTANCE); } } // helper for verifying that correct objects were journaled to the output stream private static void verifyJournal(InodeTree root, List<Inode<?>> journaled) throws Exception { Iterator<alluxio.proto.journal.Journal.JournalEntry> it = root.getJournalEntryIterator(); for (Inode<?> node : journaled) { Assert.assertTrue(it.hasNext()); Assert.assertEquals(node.toJournalEntry(), it.next()); } Assert.assertTrue(!it.hasNext()); } // verify that the tree has the given children private static void verifyChildrenNames(InodeTree tree, LockedInodePath inodePath, Set<String> childNames) throws Exception { try (InodeLockList lockList = tree .lockDescendants(inodePath, InodeTree.LockMode.READ)) { List<Inode<?>> children = lockList.getInodes(); Assert.assertEquals(childNames.size(), children.size()); for (Inode<?> child : children) { Assert.assertTrue(childNames.contains(child.getName())); } } } }