/* * 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.shell; import alluxio.AlluxioURI; import alluxio.Constants; import alluxio.LocalAlluxioClusterResource; import alluxio.client.WriteType; import alluxio.client.file.FileSystem; import alluxio.client.file.FileSystemTestUtils; import alluxio.client.file.options.DeleteOptions; import alluxio.exception.AlluxioException; import alluxio.master.LocalAlluxioCluster; import alluxio.shell.command.ShellCommand; import org.apache.commons.io.FileUtils; import org.apache.thrift.TException; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.reflections.Reflections; import java.io.File; import java.io.IOException; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; /** * Unit tests on {@link alluxio.shell.AlluxioShellUtils}. * * Note that the test case for {@link AlluxioShellUtils#validatePath(String)} is already covered * in {@link AlluxioShellUtils#getFilePath(String)}. Hence only getFilePathTest is specified. */ public final class AlluxioShellUtilsTest { public static final String TEST_DIR = "/testDir"; @Rule public LocalAlluxioClusterResource mLocalAlluxioClusterResource = new LocalAlluxioClusterResource.Builder().build(); private FileSystem mFileSystem = null; @Before public final void before() throws Exception { mFileSystem = mLocalAlluxioClusterResource.get().getClient(); } @Test public void getFilePath() throws IOException { String[] paths = new String[] {Constants.HEADER + "localhost:19998/dir", Constants.HEADER_FT + "localhost:19998/dir", "/dir", "dir"}; String expected = "/dir"; for (String path : paths) { String result = AlluxioShellUtils.getFilePath(path); Assert.assertEquals(expected, result); } } /** Type of file system. */ public enum FsType { TFS, LOCAL } // TODO(binfan): rename resetFileHierarchy to resetFileSystemHierarchy // TODO(binfan): use option idiom for FileSystem fs, WriteType writeType // TODO(binfan): move those static methods to a util class public String resetFileHierarchy() throws IOException, AlluxioException { return resetFileHierarchy(mFileSystem); } /** * Resets the file hierarchy. * * @param fs the file system * @return the test directory */ public static String resetFileHierarchy(FileSystem fs) throws IOException, AlluxioException { return resetFileHierarchy(fs, WriteType.MUST_CACHE); } /** * Resets the file hierarchy. * * @param fs the file system * @param writeType write types for creating a file in Alluxio * @return the test directory */ public static String resetFileHierarchy(FileSystem fs, WriteType writeType) throws IOException, AlluxioException { /** * Generate such local structure TEST_DIR * ├── foo | * ├── foobar1 * └── foobar2 * ├── bar | * └── foobar3 * └── foobar4 */ if (fs.exists(new AlluxioURI(TEST_DIR))) { fs.delete(new AlluxioURI(TEST_DIR), DeleteOptions.defaults().setRecursive(true)); } fs.createDirectory(new AlluxioURI(TEST_DIR)); fs.createDirectory(new AlluxioURI(TEST_DIR + "/foo")); fs.createDirectory(new AlluxioURI(TEST_DIR + "/bar")); FileSystemTestUtils.createByteFile(fs, TEST_DIR + "/foo/foobar1", writeType, 10); FileSystemTestUtils.createByteFile(fs, TEST_DIR + "/foo/foobar2", writeType, 20); FileSystemTestUtils.createByteFile(fs, TEST_DIR + "/bar/foobar3", writeType, 30); FileSystemTestUtils.createByteFile(fs, TEST_DIR + "/foobar4", writeType, 40); return TEST_DIR; } /** * Resets the local file hierarchy. * * @return the local test directory */ public String resetLocalFileHierarchy() throws IOException { return resetLocalFileHierarchy(mLocalAlluxioClusterResource.get()); } /** * Resets the local file hierarchy. * * @param localAlluxioCluster local Alluxio cluster for tests * @return the local test directory */ public static String resetLocalFileHierarchy(LocalAlluxioCluster localAlluxioCluster) throws IOException { /** * Generate such local structure TEST_DIR * ├── foo | * ├── foobar1 * └── foobar2 * ├── bar | * └── foobar3 * └── foobar4 */ FileUtils.deleteDirectory(new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR)); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR).mkdir(); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR + "/foo").mkdir(); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR + "/bar").mkdir(); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR + "/foo/foobar1").createNewFile(); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR + "/foo/foobar2").createNewFile(); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR + "/bar/foobar3").createNewFile(); new File(localAlluxioCluster.getAlluxioHome() + TEST_DIR + "/foobar4").createNewFile(); return localAlluxioCluster.getAlluxioHome() + TEST_DIR; } /** * Gets all the file paths that match the inputPath depending on fsType. * * @param path the input path * @param fsType the type of file system * @return a list of files that matches inputPath */ public List<String> getPaths(String path, FsType fsType) throws IOException, TException { List<String> ret = null; if (fsType == FsType.TFS) { List<AlluxioURI> tPaths = AlluxioShellUtils.getAlluxioURIs(mFileSystem, new AlluxioURI(path)); ret = new ArrayList<>(tPaths.size()); for (AlluxioURI tPath : tPaths) { ret.add(tPath.getPath()); } } else if (fsType == FsType.LOCAL) { List<File> tPaths = AlluxioShellUtils.getFiles(path); ret = new ArrayList<>(tPaths.size()); for (File tPath : tPaths) { ret.add(tPath.getPath()); } } Collections.sort(ret); return ret; } /** * Resets the file hierarchy depending on the type of file system. * * @param fsType the type of file system * @return the test directory, null if the fsType is invalid */ public String resetFsHierarchy(FsType fsType) throws IOException, AlluxioException { if (fsType == FsType.TFS) { return resetFileHierarchy(); } else if (fsType == FsType.LOCAL) { return resetLocalFileHierarchy(); } else { return null; } } @Test public void getPath() throws IOException, AlluxioException, TException { for (FsType fsType : FsType.values()) { String rootDir = resetFsHierarchy(fsType); List<String> tl1 = getPaths(rootDir + "/foo", fsType); Assert.assertEquals(tl1.size(), 1); Assert.assertEquals(tl1.get(0), rootDir + "/foo"); // Trailing slash List<String> tl2 = getPaths(rootDir + "/foo/", fsType); Assert.assertEquals(tl2.size(), 1); Assert.assertEquals(tl2.get(0), rootDir + "/foo"); // Wildcard List<String> tl3 = getPaths(rootDir + "/foo/*", fsType); Assert.assertEquals(tl3.size(), 2); Assert.assertEquals(tl3.get(0), rootDir + "/foo/foobar1"); Assert.assertEquals(tl3.get(1), rootDir + "/foo/foobar2"); // Trailing slash + wildcard List<String> tl4 = getPaths(rootDir + "/foo/*/", fsType); Assert.assertEquals(tl4.size(), 2); Assert.assertEquals(tl4.get(0), rootDir + "/foo/foobar1"); Assert.assertEquals(tl4.get(1), rootDir + "/foo/foobar2"); // Multiple wildcards List<String> tl5 = getPaths(rootDir + "/*/foo*", fsType); Assert.assertEquals(tl5.size(), 3); Assert.assertEquals(tl5.get(0), rootDir + "/bar/foobar3"); Assert.assertEquals(tl5.get(1), rootDir + "/foo/foobar1"); Assert.assertEquals(tl5.get(2), rootDir + "/foo/foobar2"); } } @Test public void match() { Assert.assertEquals(AlluxioShellUtils.match("/a/b/c", "/a/*"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c", "/a/*/"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c", "/a/*/c"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c", "/a/*/*"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c", "/a/*/*/"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c/", "/a/*/*/"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c/", "/a/*/*"), true); Assert.assertEquals(AlluxioShellUtils.match("/foo/bar/foobar/", "/foo*/*"), true); Assert.assertEquals(AlluxioShellUtils.match("/foo/bar/foobar/", "/*/*/foobar"), true); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c/", "/b/*"), false); Assert.assertEquals(AlluxioShellUtils.match("/", "/*/*"), false); Assert.assertEquals(AlluxioShellUtils.match("/a/b/c", "*"), true); Assert.assertEquals(AlluxioShellUtils.match("/", "/*"), true); } @Test public void loadCommands() { Map<String, ShellCommand> map = AlluxioShellUtils.loadCommands(mFileSystem); String pkgName = ShellCommand.class.getPackage().getName(); Reflections reflections = new Reflections(pkgName); Set<Class<? extends ShellCommand>> cmdSet = reflections.getSubTypesOf(ShellCommand.class); for (Map.Entry<String, ShellCommand> entry : map.entrySet()) { Assert.assertEquals(entry.getValue().getCommandName(), entry.getKey()); Assert.assertEquals(cmdSet.contains(entry.getValue().getClass()), true); } int expectSize = 0; for (Class<? extends ShellCommand> cls : cmdSet) { if (!Modifier.isAbstract(cls.getModifiers())) { expectSize++; } } Assert.assertEquals(expectSize, map.size()); } }