/* * 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.ignite.internal.processors.igfs; import org.apache.commons.io.IOUtils; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteFileSystem; import org.apache.ignite.cache.CacheWriteSynchronizationMode; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.FileSystemConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.igfs.IgfsDirectoryNotEmptyException; import org.apache.ignite.igfs.IgfsException; import org.apache.ignite.igfs.IgfsFile; import org.apache.ignite.igfs.IgfsGroupDataBlocksKeyMapper; import org.apache.ignite.igfs.IgfsInputStream; import org.apache.ignite.igfs.IgfsOutputStream; import org.apache.ignite.igfs.IgfsPath; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.processors.cache.GridCacheAdapter; import org.apache.ignite.internal.util.lang.GridAbsPredicate; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import org.apache.ignite.testframework.GridTestUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.cache.Cache; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; import static org.apache.ignite.cache.CacheMode.PARTITIONED; import static org.apache.ignite.cache.CacheMode.REPLICATED; /** * Tests for {@link IgfsProcessor}. */ public class IgfsProcessorSelfTest extends IgfsCommonAbstractTest { /** Test IP finder. */ private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** Random numbers generator. */ protected final SecureRandom rnd = new SecureRandom(); /** File system. */ protected IgniteFileSystem igfs; /** Meta cache. */ private GridCacheAdapter<Object, Object> metaCache; /** Meta cache name. */ private String metaCacheName; /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { IgniteEx grid = grid(0); igfs = grid.fileSystem(igfsName()); FileSystemConfiguration[] cfgs = grid.configuration().getFileSystemConfiguration(); assert cfgs.length == 1; metaCacheName = cfgs[0].getMetaCacheConfiguration().getName(); metaCache = ((IgniteKernal)grid).internalCache(metaCacheName); } /** {@inheritDoc} */ @Override protected void afterTest() throws Exception { super.afterTest(); igfs.clear(); } /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { startGrids(nodesCount()); } /** {@inheritDoc} */ @Override protected void afterTestsStopped() throws Exception { stopAllGrids(); } /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); TcpDiscoverySpi discoSpi = new TcpDiscoverySpi(); discoSpi.setIpFinder(IP_FINDER); cfg.setDiscoverySpi(discoSpi); FileSystemConfiguration igfsCfg = new FileSystemConfiguration(); igfsCfg.setMetaCacheConfiguration(cacheConfiguration("meta")); igfsCfg.setDataCacheConfiguration(cacheConfiguration("data")); igfsCfg.setName("igfs"); cfg.setFileSystemConfiguration(igfsCfg); return cfg; } /** {@inheritDoc} */ protected CacheConfiguration cacheConfiguration(@NotNull String cacheName) { CacheConfiguration cacheCfg = defaultCacheConfiguration(); cacheCfg.setName(cacheName); if ("meta".equals(cacheName)) cacheCfg.setCacheMode(REPLICATED); else { cacheCfg.setCacheMode(PARTITIONED); cacheCfg.setNearConfiguration(null); cacheCfg.setBackups(0); cacheCfg.setAffinityMapper(new IgfsGroupDataBlocksKeyMapper(128)); } cacheCfg.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); cacheCfg.setAtomicityMode(TRANSACTIONAL); return cacheCfg; } /** @return Test nodes count. */ public int nodesCount() { return 1; } /** @return FS name. */ public String igfsName() { return "igfs"; } /** @throws Exception If failed. */ public void testigfsEnabled() throws Exception { IgniteFileSystem igfs = grid(0).fileSystem(igfsName()); assertNotNull(igfs); } /** * Test properties management in meta-cache. * * @throws Exception If failed. */ public void testUpdateProperties() throws Exception { IgfsPath p = path("/tmp/my"); igfs.mkdirs(p); Map<String, String> oldProps = igfs.info(p).properties(); igfs.update(p, F.asMap("a", "1")); igfs.update(p, F.asMap("b", "2")); assertEquals("1", igfs.info(p).property("a")); assertEquals("2", igfs.info(p).property("b")); igfs.update(p, F.asMap("b", "3")); Map<String, String> expProps = new HashMap<>(oldProps); expProps.put("a", "1"); expProps.put("b", "3"); assertEquals("3", igfs.info(p).property("b")); assertEquals(expProps, igfs.info(p).properties()); assertEquals("5", igfs.info(p).property("c", "5")); assertUpdatePropertiesFails(null, null, NullPointerException.class, "Ouch! Argument cannot be null"); assertUpdatePropertiesFails(p, null, NullPointerException.class, "Ouch! Argument cannot be null"); assertUpdatePropertiesFails(null, F.asMap("x", "9"), NullPointerException.class, "Ouch! Argument cannot be null"); assertUpdatePropertiesFails(p, Collections.<String, String>emptyMap(), IllegalArgumentException.class, "Ouch! Argument is invalid"); } /** @throws Exception If failed. */ public void testCreate() throws Exception { IgfsPath path = path("/file"); try (IgfsOutputStream os = igfs.create(path, false)) { assert os != null; IgfsFileImpl info = (IgfsFileImpl)igfs.info(path); for (int i = 0; i < nodesCount(); i++) { IgfsEntryInfo fileInfo = (IgfsEntryInfo)grid(i).cachex(metaCacheName).localPeek(info.fileId(), null, null); assertNotNull(fileInfo); assertNotNull(fileInfo.listing()); } } finally { igfs.delete(path("/"), true); } } /** * Test make directories. * * @throws Exception In case of any exception. */ public void testMakeListDeleteDirs() throws Exception { assertListDir("/"); igfs.mkdirs(path("/ab/cd/ef")); assertListDir("/", "ab"); assertListDir("/ab", "cd"); assertListDir("/ab/cd", "ef"); igfs.mkdirs(path("/ab/ef")); igfs.mkdirs(path("/cd/ef")); igfs.mkdirs(path("/cd/gh")); igfs.mkdirs(path("/ef")); igfs.mkdirs(path("/ef/1")); igfs.mkdirs(path("/ef/2")); igfs.mkdirs(path("/ef/3")); assertListDir("/", "ef", "ab", "cd"); assertListDir("/ab", "cd", "ef"); assertListDir("/ab/cd", "ef"); assertListDir("/ab/cd/ef"); assertListDir("/cd", "ef", "gh"); assertListDir("/cd/ef"); assertListDir("/ef", "1", "2", "3"); igfs.delete(path("/ef/2"), false); assertListDir("/", "ef", "ab", "cd"); assertListDir("/ef", "1", "3"); // Delete should return false for non-existing paths. assertFalse(igfs.delete(path("/ef/2"), false)); assertListDir("/", "ef", "ab", "cd"); assertListDir("/ef", "1", "3"); GridTestUtils.assertThrows(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.delete(path("/ef"), false); return null; } }, IgfsDirectoryNotEmptyException.class, null); assertListDir("/", "ef", "ab", "cd"); assertListDir("/ef", "1", "3"); igfs.delete(path("/ef"), true); assertListDir("/", "ab", "cd"); } /** * Test make directories in multi-threaded environment. * * @throws Exception In case of any exception. */ @SuppressWarnings("TooBroadScope") public void testMakeListDeleteDirsMultithreaded() throws Exception { assertListDir("/"); final int max = 2 * 1000; final int threads = 50; final AtomicInteger cnt = new AtomicInteger(); info("Create directories: " + max); GridTestUtils.runMultiThreaded(new Callable<Object>() { @Override public Object call() throws Exception { for (int cur = cnt.incrementAndGet(); cur < max; cur = cnt.incrementAndGet()) igfs.mkdirs(path(cur)); return null; } }, threads, "grid-test-make-directories"); info("Validate directories were created."); cnt.set(0); // Reset counter. GridTestUtils.runMultiThreaded(new Callable<Object>() { @Override public Object call() throws Exception { for (int cur = cnt.incrementAndGet(); cur < max; cur = cnt.incrementAndGet()) { IgfsFile info = igfs.info(path(cur)); assertNotNull("Expects file exist: " + cur, info); assertTrue("Expects file is a directory: " + cur, info.isDirectory()); } return null; } }, threads, "grid-test-check-directories-exist"); info("Validate directories removing."); cnt.set(0); // Reset counter. GridTestUtils.runMultiThreaded(new Callable<Object>() { @Override public Object call() throws Exception { for (int cur = cnt.incrementAndGet(); cur < max; cur = cnt.incrementAndGet()) igfs.delete(path(cur), true); return null; } }, threads, "grid-test-delete-directories"); } /** @throws Exception If failed. */ public void testBasicOps() throws Exception { // Create directories. igfs.mkdirs(path("/A/B1/C1")); for (Object key : metaCache.keySet()) info("Entry in cache [key=" + key + ", val=" + metaCache.get(key) + ']'); igfs.mkdirs(path("/A/B1/C2")); igfs.mkdirs(path("/A/B1/C3")); igfs.mkdirs(path("/A/B2/C1")); igfs.mkdirs(path("/A/B2/C2")); igfs.mkdirs(path("/A1/B1/C1")); igfs.mkdirs(path("/A1/B1/C2")); igfs.mkdirs(path("/A1/B1/C3")); igfs.mkdirs(path("/A2/B2/C1")); igfs.mkdirs(path("/A2/B2/C2")); for (Object key : metaCache.keySet()) info("Entry in cache [key=" + key + ", val=" + metaCache.get(key) + ']'); // Check existence. assert igfs.exists(path("/A/B1/C1")); // List items. Collection<IgfsPath> paths = igfs.listPaths(path("/")); assert paths.size() == 3 : "Unexpected paths: " + paths; paths = igfs.listPaths(path("/A")); assert paths.size() == 2 : "Unexpected paths: " + paths; paths = igfs.listPaths(path("/A/B1")); assert paths.size() == 3 : "Unexpected paths: " + paths; igfs.delete(path("/A1/B1/C1"), false); assertNull(igfs.info(path("/A1/B1/C1"))); igfs.delete(path("/A1/B1/C2"), false); assertNull(igfs.info(path("/A1/B1/C2"))); igfs.delete(path("/A1/B1/C3"), false); assertNull(igfs.info(path("/A1/B1/C3"))); assertTrue(F.isEmpty(igfs.listPaths(path("/A1/B1")))); igfs.delete(path("/A2/B2"), true); assertNull(igfs.info(path("/A2/B2"))); assertTrue(F.isEmpty(igfs.listPaths(path("/A2")))); assertEquals(Arrays.asList(path("/A"), path("/A1"), path("/A2")), sorted(igfs.listPaths(path("/")))); // Delete root when it is not empty: igfs.delete(path("/"), true); igfs.delete(path("/"), false); igfs.delete(path("/A"), true); igfs.delete(path("/A1"), true); igfs.delete(path("/A2"), true); assertTrue(F.isEmpty(igfs.listPaths(path("/")))); // Delete root when it is empty: igfs.delete(path("/"), false); igfs.delete(path("/"), true); assertTrue(F.isEmpty(igfs.listPaths(path("/")))); for (Cache.Entry<Object, Object> e : metaCache) info("Entry in cache [key=" + e.getKey() + ", val=" + e.getValue() + ']'); } /** * Ensure correct size calculation. * * @throws Exception If failed. */ public void testSize() throws Exception { IgfsPath dir1 = path("/dir1"); IgfsPath subDir1 = path("/dir1/subdir1"); IgfsPath dir2 = path("/dir2"); IgfsPath fileDir1 = path("/dir1/file"); IgfsPath fileSubdir1 = path("/dir1/subdir1/file"); IgfsPath fileDir2 = path("/dir2/file"); IgfsOutputStream os = igfs.create(fileDir1, false); os.write(new byte[1000]); os.close(); os = igfs.create(fileSubdir1, false); os.write(new byte[2000]); os.close(); os = igfs.create(fileDir2, false); os.write(new byte[4000]); os.close(); assert igfs.size(fileDir1) == 1000; assert igfs.size(fileSubdir1) == 2000; assert igfs.size(fileDir2) == 4000; assert igfs.size(dir1) == 3000; assert igfs.size(subDir1) == 2000; assert igfs.size(dir2) == 4000; } /** * Convert collection into sorted list. * * @param col Unsorted collection. * @return Sorted collection. */ private <T extends Comparable<T>> List<T> sorted(Collection<T> col) { List<T> list = new ArrayList<>(col); Collections.sort(list); return list; } /** @throws Exception If failed. */ public void testRename() throws Exception { // Create directories. igfs.mkdirs(path("/A/B1/C1")); for (Object key : metaCache.keySet()) info("Entry in cache [key=" + key + ", val=" + metaCache.get(key) + ']'); // Move under itself. GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.rename(path("/A/B1/C1"), path("/A/B1/C1/C2")); return null; } }, IgfsException.class, null); // Move under itself. GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.rename(path("/A/B1/C1"), path("/A/B1/C1/D/C2")); return null; } }, IgfsException.class, null); // Move under itself. GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.rename(path("/A/B1/C1"), path("/A/B1/C1/D/E/C2")); return null; } }, IgfsException.class, null); /// // F6 > Enter > Tab x N times // "I like to move it, move it..." // Collection<IgniteBiTuple<String, String>> chain = Arrays.asList( F.t("/A/B1/C1", "/A/B1/C2"), F.t("/A/B1", "/A/B2"), F.t("/A", "/Q"), //F.t("/Q/B2/C2", "/C3"), F.t("/Q/B2/C2", "/Q/B2/C1"), F.t("/Q/B2", "/Q/B1"), F.t("/Q", "/A"), //F.t("/C3", "/A/B1/C1") F.t("/A/B1/C1", "/"), F.t("/C1", "/A/B1") ); final IgfsPath root = path("/"); for (IgniteBiTuple<String, String> e : chain) { final IgfsPath p1 = path(e.get1()); final IgfsPath p2 = path(e.get2()); assertTrue("Entry: " + e, igfs.exists(p1)); igfs.rename(p1, p2); assertFalse("Entry: " + e, igfs.exists(p1)); assertTrue("Entry: " + e, igfs.exists(p2)); // Test root rename. GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.rename(root, p1); return null; } }, IgfsException.class, null); // Test root rename. GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.rename(p1, root); return null; } }, IgfsException.class, null); // Test root rename. if (!root.equals(p2)) { GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.rename(root, p2); return null; } }, IgfsException.class, null); } // Test same rename. igfs.rename(p1, p1); igfs.rename(p2, p2); } // List items. assertEquals(Arrays.asList(path("/A")), sorted(igfs.listPaths(root))); assertEquals(Arrays.asList(path("/A/B1")), sorted(igfs.listPaths(path("/A")))); assertEquals(Arrays.asList(path("/A/B1/C1")), sorted(igfs.listPaths(path("/A/B1")))); String text = "Test long number: " + rnd.nextLong(); // Create file. assertEquals(text, create("/A/a", false, text)); // Validate renamed during reading. try (IgfsInputStream in0 = igfs.open(path("/A/a"))) { // Rename file. igfs.rename(path("/A/a"), path("/b")); assertEquals(text, IOUtils.toString(in0, UTF_8)); } // Validate after renamed. assertOpenFails("/A/a", "File not found"); assertEquals(text, read("/b")); // Cleanup. igfs.clear(); assertTrue(F.isEmpty(igfs.listPaths(root))); } /** * @param path Path. * @return IGFS path. */ private IgfsPath path(String path) { assert path != null; return new IgfsPath(path); } /** * @param i Path index. * @return IGFS path. */ private IgfsPath path(long i) { //return path(String.format("/%d", i)); return path(String.format("/%d/q/%d/%d", i % 10, (i / 10) % 10, i)); } /** @throws Exception If failed. */ public void testCreateOpenAppend() throws Exception { // Error - path points to root directory. assertCreateFails("/", false); // Create directories. igfs.mkdirs(path("/A/B1/C1")); // Error - path points to directory. for (String path : Arrays.asList("/A", "/A/B1", "/A/B1/C1")) { assertCreateFails(path, false); assertCreateFails(path, true); assertAppendFails(path, false); assertAppendFails(path, true); assertOpenFails(path, "Failed to open file (not a file)"); } String text1 = "Test long number #1: " + rnd.nextLong(); String text2 = "Test long number #2: " + rnd.nextLong(); // Error - parent does not exist. for (String path : Arrays.asList("/A/a", "/A/B1/a", "/A/B1/C1/a")) { // Error - file doesn't exist. assertOpenFails(path, "File not found"); assertAppendFails(path, false); // Create new and write. assertEquals(text1, create(path, false, text1)); // Error - file already exists. assertCreateFails(path, false); // Overwrite existent. assertEquals(text2, create(path, true, text2)); // Append text. assertEquals(text2 + text1, append(path, false, text1)); // Append text. assertEquals(text2 + text1 + text2, append(path, true, text2)); // Delete this file. igfs.delete(path(path), true); // Error - file doesn't exist. assertOpenFails(path, "File not found"); assertAppendFails(path, false); // Create with append. assertEquals(text1, append(path, true, text1)); // Append. for (String full = text1, cur = ""; full.length() < 10000; cur = ", long=" + rnd.nextLong()) assertEquals(full += cur, append(path, rnd.nextBoolean(), cur)); igfs.delete(path(path), false); } } /** @throws Exception If failed. */ @SuppressWarnings("BusyWait") public void testDeleteCacheConsistency() throws Exception { IgfsPath path = new IgfsPath("/someFile"); String metaCacheName = grid(0).igfsx("igfs").configuration().getMetaCacheConfiguration().getName(); String dataCacheName = grid(0).igfsx("igfs").configuration().getDataCacheConfiguration().getName(); try (IgfsOutputStream out = igfs.create(path, true)) { out.write(new byte[10 * 1024 * 1024]); } IgniteUuid fileId = U.field(igfs.info(path), "fileId"); GridCacheAdapter<IgniteUuid, IgfsEntryInfo> metaCache = ((IgniteKernal)grid(0)).internalCache(metaCacheName); GridCacheAdapter<IgfsBlockKey, byte[]> dataCache = ((IgniteKernal)grid(0)).internalCache(dataCacheName); IgfsEntryInfo info = metaCache.get(fileId); assertNotNull(info); assertTrue(info.isFile()); assertNotNull(metaCache.get(info.id())); IgfsDataManager dataMgr = ((IgfsEx)igfs).context().data(); for (int i = 0; i < info.blocksCount(); i++) assertNotNull(dataCache.get(dataMgr.blockKey(i, info))); igfs.delete(path, true); for (int i = 0; i < 25; i++) { if (metaCache.get(info.id()) == null) break; U.sleep(100); } assertNull(metaCache.get(info.id())); for (int i = 0; i < 10; i++) { boolean doBreak = true; for (int j = 0; j < info.blocksCount(); j++) { if (dataCache.get(dataMgr.blockKey(i, info)) != null) { doBreak = false; break; } } if (doBreak) break; else Thread.sleep(100); } for (int i = 0; i < info.blocksCount(); i++) assertNull(dataCache.get(new IgfsBlockKey(info.id(), null, false, i))); } /** @throws Exception If failed. */ public void testCreateAppendLongData1() throws Exception { checkCreateAppendLongData(123, 1024, 100); } /** @throws Exception If failed. */ public void testCreateAppendLongData2() throws Exception { checkCreateAppendLongData(123 + 1024, 1024, 100); } /** @throws Exception If failed. */ public void testCreateAppendLongData3() throws Exception { checkCreateAppendLongData(123, 1024, 1000); } /** @throws Exception If failed. */ public void testCreateAppendLongData4() throws Exception { checkCreateAppendLongData(123 + 1024, 1024, 1000); } /** * Test format operation on non-empty file system. * * @throws Exception If failed. */ public void testFormatNonEmpty() throws Exception { String dirPath = "/A/B/C"; igfs.mkdirs(path(dirPath)); String filePath = "/someFile"; create(filePath, false, "Some text."); igfs.clear(); assert !igfs.exists(path(dirPath)); assert !igfs.exists(path(filePath)); GridTestUtils.waitForCondition(new GridAbsPredicate() { @Override public boolean apply() { int metaSize = 0; for (Object metaId : grid(0).cachex(igfs.configuration().getMetaCacheConfiguration().getName()) .keySet()) { if (!IgfsUtils.isRootOrTrashId((IgniteUuid)metaId)) metaSize++; } return metaSize == 0; } }, 5000); } /** * Test format operation on empty file system. * * @throws Exception If failed. */ public void testFormatEmpty() throws Exception { igfs.clear(); } /** * @param chunkSize Chunk size. * @param bufSize Buffer size. * @param cnt Count. * @throws Exception If failed. */ private void checkCreateAppendLongData(int chunkSize, int bufSize, int cnt) throws Exception { IgfsPath path = new IgfsPath("/someFile"); byte[] buf = new byte[chunkSize]; for (int i = 0; i < buf.length; i++) buf[i] = (byte)(i * i); IgfsOutputStream os = igfs.create(path, bufSize, true, null, 0, 1024, null); try { for (int i = 0; i < cnt; i++) os.write(buf); os.flush(); } finally { os.close(); } os = igfs.append(path, chunkSize, false, null); try { for (int i = 0; i < cnt; i++) os.write(buf); os.flush(); } finally { os.close(); } byte[] readBuf = new byte[chunkSize]; try (IgfsInputStream in = igfs.open(path)) { long pos = 0; for (int k = 0; k < 2 * cnt; k++) { in.readFully(pos, readBuf); for (int i = 0; i < readBuf.length; i++) assertEquals(buf[i], readBuf[i]); pos += readBuf.length; } } } /** * Create file and write specified text to. * * @param path File path to create. * @param overwrite Overwrite file if it already exists. * @param text Text to write into file. * @return Content of this file. * @throws IgniteCheckedException In case of error. */ private String create(String path, boolean overwrite, String text) throws Exception { try (IgfsOutputStream out = igfs.create(path(path), overwrite)) { IOUtils.write(text, out, UTF_8); } assertNotNull(igfs.info(path(path))); return read(path); } /** * Appent text to the file. * * @param path File path to create. * @param create Create file if it doesn't exist yet. * @param text Text to append to file. * @return Content of this file. * @throws IgniteCheckedException In case of error. */ private String append(String path, boolean create, String text) throws Exception { try (IgfsOutputStream out = igfs.append(path(path), create)) { IOUtils.write(text, out, UTF_8); } assertNotNull(igfs.info(path(path))); return read(path); } /** * Read content of the file. * * @param path File path to read. * @return Content of this file. * @throws IgniteCheckedException In case of error. */ private String read(String path) throws Exception { try (IgfsInputStream in = igfs.open(path(path))) { return IOUtils.toString(in, UTF_8); } } /** * Test expected failures for 'update properties' operation. * * @param path Path to the file. * @param props File properties to set. * @param msg Failure message if expected exception was not thrown. */ private void assertUpdatePropertiesFails(@Nullable final IgfsPath path, @Nullable final Map<String, String> props, Class<? extends Throwable> cls, @Nullable String msg) { GridTestUtils.assertThrows(log, new Callable() { @Override public Object call() throws Exception { return igfs.update(path, props); } }, cls, msg); } /** * Test expected failures for 'create' operation. * * @param path File path to create. * @param overwrite Overwrite file if it already exists. Note: you cannot overwrite an existent directory. */ private void assertCreateFails(final String path, final boolean overwrite) { GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.create(path(path), overwrite); return false; } }, IgfsException.class, null); } /** * Test expected failures for 'append' operation. * * @param path File path to append. * @param create Create file if it doesn't exist yet. */ private void assertAppendFails(final String path, final boolean create) { GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.append(path(path), create); return false; } }, IgfsException.class, null); } /** * Test expected failures for 'open' operation. * * @param path File path to read. * @param msg Failure message if expected exception was not thrown. */ private void assertOpenFails(final String path, @Nullable String msg) { GridTestUtils.assertThrowsInherited(log, new Callable<Object>() { @Override public Object call() throws Exception { igfs.open(path(path)); return false; } }, IgniteException.class, msg); } /** * Validate directory listing. * * @param path Directory path to validate listing for. * @param item List of directory items. */ private void assertListDir(String path, String... item) { Collection<IgfsFile> files = igfs.listFiles(new IgfsPath(path)); List<String> names = new ArrayList<>(item.length); for (IgfsFile file : files) names.add(file.path().name()); Arrays.sort(item); Collections.sort(names); assertEquals(Arrays.asList(item), names); } }