(TWILL-158) Added FileContext Location and LocationFactory - Added new unit-tests. - Minor improvement on HDFSLocationFactory to handle creation URI correctly
This closes #73 on GitHub. Signed-off-by: Terence Yim <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/incubator-twill/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-twill/commit/388a6d92 Tree: http://git-wip-us.apache.org/repos/asf/incubator-twill/tree/388a6d92 Diff: http://git-wip-us.apache.org/repos/asf/incubator-twill/diff/388a6d92 Branch: refs/heads/site Commit: 388a6d922dd89dd8e1f5a9fed5aefe265ef2eeed Parents: b80f9b8 Author: Terence Yim <[email protected]> Authored: Thu Dec 24 12:38:03 2015 +0800 Committer: Terence Yim <[email protected]> Committed: Tue Jan 5 14:54:24 2016 -0800 ---------------------------------------------------------------------- .../twill/filesystem/LocalLocationFactory.java | 4 +- .../twill/filesystem/FileContextLocation.java | 219 +++++++++++++++++++ .../filesystem/FileContextLocationFactory.java | 119 ++++++++++ .../apache/twill/filesystem/HDFSLocation.java | 2 +- .../twill/filesystem/HDFSLocationFactory.java | 18 +- .../filesystem/FileContextLocationTest.java | 50 +++++ .../twill/filesystem/HDFSLocationTest.java | 6 +- .../twill/filesystem/LocalLocationTest.java | 17 +- .../twill/filesystem/LocationTestBase.java | 68 +++++- 9 files changed, 477 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java ---------------------------------------------------------------------- diff --git a/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java index 82847b2..8e7ab8b 100644 --- a/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java +++ b/twill-common/src/main/java/org/apache/twill/filesystem/LocalLocationFactory.java @@ -31,7 +31,7 @@ public final class LocalLocationFactory implements LocationFactory { * Constructs a LocalLocationFactory that Location created will be relative to system root. */ public LocalLocationFactory() { - this(new File("/")); + this(new File(File.separator)); } public LocalLocationFactory(File basePath) { @@ -40,7 +40,7 @@ public final class LocalLocationFactory implements LocationFactory { @Override public Location create(String path) { - return new LocalLocation(this, new File(basePath, path)); + return create(new File(basePath, path).toURI()); } @Override http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocation.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocation.java b/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocation.java new file mode 100644 index 0000000..f92954e --- /dev/null +++ b/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocation.java @@ -0,0 +1,219 @@ +/* + * 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.twill.filesystem; + +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import org.apache.hadoop.fs.CreateFlag; +import org.apache.hadoop.fs.FileAlreadyExistsException; +import org.apache.hadoop.fs.FileContext; +import org.apache.hadoop.fs.FileStatus; +import org.apache.hadoop.fs.Options; +import org.apache.hadoop.fs.ParentNotDirectoryException; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.RemoteIterator; +import org.apache.hadoop.fs.permission.FsPermission; +import org.apache.hadoop.hdfs.HAUtil; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import javax.annotation.Nullable; + +/** + * An implementation of {@link Location} using {@link FileContext}. + */ +final class FileContextLocation implements Location { + + private final FileContextLocationFactory locationFactory; + private final FileContext fc; + private final Path path; + + FileContextLocation(FileContextLocationFactory locationFactory, FileContext fc, Path path) { + this.locationFactory = locationFactory; + this.fc = fc; + this.path = path; + } + + @Override + public boolean exists() throws IOException { + return fc.util().exists(path); + } + + @Override + public String getName() { + return path.getName(); + } + + @Override + public boolean createNew() throws IOException { + try { + fc.create(path, EnumSet.of(CreateFlag.CREATE), Options.CreateOpts.createParent()).close(); + return true; + } catch (FileAlreadyExistsException e) { + return false; + } + } + + @Override + public InputStream getInputStream() throws IOException { + return fc.open(path); + } + + @Override + public OutputStream getOutputStream() throws IOException { + return fc.create(path, EnumSet.of(CreateFlag.CREATE, CreateFlag.OVERWRITE), Options.CreateOpts.createParent()); + } + + @Override + public OutputStream getOutputStream(String permission) throws IOException { + return fc.create(path, EnumSet.of(CreateFlag.CREATE, CreateFlag.OVERWRITE), + Options.CreateOpts.perms(new FsPermission(permission)), + Options.CreateOpts.createParent()); + } + + @Override + public Location append(String child) throws IOException { + if (child.startsWith("/")) { + child = child.substring(1); + } + return new FileContextLocation(locationFactory, fc, new Path(URI.create(path.toUri() + "/" + child))); + } + + @Override + public Location getTempFile(String suffix) throws IOException { + Path path = new Path( + URI.create(this.path.toUri() + "." + UUID.randomUUID() + (suffix == null ? TEMP_FILE_SUFFIX : suffix))); + return new FileContextLocation(locationFactory, fc, path); + } + + @Override + public URI toURI() { + // In HA mode, the path URI returned by path created through FileContext is incompatible with the FileSystem, + // which is used inside Hadoop. It is due to the fact that FileContext is not HA aware and it always + // append "port" to the path URI, while the DistributedFileSystem always use the cluster logical + // name, which doesn't allow having port in it. + URI uri = path.toUri(); + if (HAUtil.isLogicalUri(locationFactory.getConfiguration(), uri)) { + try { + // Need to strip out the port if in HA + return new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), + -1, uri.getPath(), uri.getQuery(), uri.getFragment()); + } catch (URISyntaxException e) { + // Shouldn't happen + throw Throwables.propagate(e); + } + } + + return uri; + } + + @Override + public boolean delete() throws IOException { + return delete(false); + } + + @Override + public boolean delete(boolean recursive) throws IOException { + return fc.delete(path, recursive); + } + + @Nullable + @Override + public Location renameTo(Location destination) throws IOException { + Path targetPath = new Path(destination.toURI()); + try { + fc.rename(path, targetPath, Options.Rename.OVERWRITE); + return new FileContextLocation(locationFactory, fc, targetPath); + } catch (FileAlreadyExistsException | FileNotFoundException | ParentNotDirectoryException e) { + return null; + } + } + + @Override + public boolean mkdirs() throws IOException { + try { + fc.mkdir(path, null, true); + return true; + } catch (FileAlreadyExistsException e) { + return false; + } + } + + @Override + public long length() throws IOException { + return fc.getFileStatus(path).getLen(); + } + + @Override + public long lastModified() throws IOException { + return fc.getFileStatus(path).getModificationTime(); + } + + @Override + public boolean isDirectory() throws IOException { + try { + return fc.getFileStatus(path).isDirectory(); + } catch (FileNotFoundException e) { + return false; + } + } + + @Override + public List<Location> list() throws IOException { + RemoteIterator<FileStatus> statuses = fc.listStatus(path); + ImmutableList.Builder<Location> result = ImmutableList.builder(); + while (statuses.hasNext()) { + FileStatus status = statuses.next(); + if (!Objects.equals(path, status.getPath())) { + result.add(new FileContextLocation(locationFactory, fc, status.getPath())); + } + } + return result.build(); + + } + + @Override + public LocationFactory getLocationFactory() { + return locationFactory; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + FileContextLocation that = (FileContextLocation) o; + return Objects.equals(path, that.path); + } + + @Override + public int hashCode() { + return Objects.hash(path); + } +} http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocationFactory.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocationFactory.java b/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocationFactory.java new file mode 100644 index 0000000..d64be71 --- /dev/null +++ b/twill-yarn/src/main/java/org/apache/twill/filesystem/FileContextLocationFactory.java @@ -0,0 +1,119 @@ +/* + * 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.twill.filesystem; + +import com.google.common.base.Preconditions; +import com.google.common.base.Throwables; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileContext; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.UnsupportedFileSystemException; + +import java.net.URI; +import java.util.Objects; + +/** + * A {@link LocationFactory} implementation that uses {@link FileContext} to create {@link Location}. + */ +public class FileContextLocationFactory implements LocationFactory { + + private final Configuration configuration; + private final FileContext fc; + private final Path pathBase; + + /** + * Same as {@link #FileContextLocationFactory(Configuration, String) FileContextLocationFactory(configuration, "/")}. + */ + public FileContextLocationFactory(Configuration configuration) { + this(configuration, "/"); + } + + /** + * Creates a new instance. + * + * @param configuration the hadoop configuration + * @param pathBase base path for all non-absolute location created through this {@link LocationFactory}. + */ + public FileContextLocationFactory(Configuration configuration, String pathBase) { + this.configuration = configuration; + this.fc = createFileContext(configuration); + this.pathBase = new Path(pathBase.startsWith("/") ? pathBase : "/" + pathBase); + } + + @Override + public Location create(String path) { + if (path.startsWith("/")) { + path = path.substring(1); + } + Path locationPath; + if (path.isEmpty()) { + locationPath = pathBase; + } else { + locationPath = new Path(path); + } + locationPath = locationPath.makeQualified(fc.getDefaultFileSystem().getUri(), pathBase); + return new FileContextLocation(this, fc, locationPath); + } + + @Override + public Location create(URI uri) { + URI contextURI = fc.getWorkingDirectory().toUri(); + if (Objects.equals(contextURI.getScheme(), uri.getScheme()) + && Objects.equals(contextURI.getAuthority(), uri.getAuthority())) { + // A full URI + return new FileContextLocation(this, fc, new Path(uri)); + } + + if (uri.isAbsolute()) { + // Needs to be of the same scheme + Preconditions.checkArgument(Objects.equals(contextURI.getScheme(), uri.getScheme()), + "Only URI with '%s' scheme is supported", contextURI.getScheme()); + Path locationPath = new Path(uri).makeQualified(fc.getDefaultFileSystem().getUri(), pathBase); + return new FileContextLocation(this, fc, locationPath); + } + + return create(uri.getPath()); + } + + @Override + public Location getHomeLocation() { + return new FileContextLocation(this, fc, fc.getHomeDirectory()); + } + + /** + * Returns the {@link FileContext} used by this {@link LocationFactory}. + */ + public FileContext getFileContext() { + return fc; + } + + /** + * Returns the {@link Configuration} used by this {@link LocationFactory}. + */ + public Configuration getConfiguration() { + return configuration; + } + + private static FileContext createFileContext(Configuration configuration) { + try { + return FileContext.getFileContext(configuration); + } catch (UnsupportedFileSystemException e) { + throw Throwables.propagate(e); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocation.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocation.java b/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocation.java index 818fe23..aa29384 100644 --- a/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocation.java +++ b/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocation.java @@ -35,7 +35,7 @@ import java.util.List; import java.util.UUID; /** - * A concrete implementation of {@link Location} for the HDFS filesystem. + * A concrete implementation of {@link Location} for the HDFS filesystem using {@link FileSystem}. */ final class HDFSLocation implements Location { private final FileSystem fs; http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocationFactory.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocationFactory.java b/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocationFactory.java index 65146a8..728de32 100644 --- a/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocationFactory.java +++ b/twill-yarn/src/main/java/org/apache/twill/filesystem/HDFSLocationFactory.java @@ -17,6 +17,7 @@ */ package org.apache.twill.filesystem; +import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; @@ -24,10 +25,14 @@ import org.apache.hadoop.fs.Path; import java.io.IOException; import java.net.URI; +import java.util.Objects; /** - * A {@link LocationFactory} that creates HDFS {@link Location}. + * A {@link LocationFactory} that creates HDFS {@link Location} using {@link FileSystem}. + * + * @deprecated Deprecated since 0.7.0. Use {@link FileContextLocationFactory} instead. */ +@Deprecated public final class HDFSLocationFactory implements LocationFactory { private final FileSystem fileSystem; @@ -63,14 +68,21 @@ public final class HDFSLocationFactory implements LocationFactory { @Override public Location create(URI uri) { - if (!uri.toString().startsWith(fileSystem.getUri().toString())) { + URI fsURI = fileSystem.getUri(); + if (Objects.equals(fsURI.getScheme(), uri.getScheme()) + && Objects.equals(fsURI.getAuthority(), uri.getAuthority())) { // It's a full URI return new HDFSLocation(this, new Path(uri)); } + if (uri.isAbsolute()) { + // Needs to be of the same scheme + Preconditions.checkArgument(Objects.equals(fsURI.getScheme(), uri.getScheme()), + "Only URI with '%s' scheme is supported", fsURI.getScheme()); return new HDFSLocation(this, new Path(fileSystem.getUri() + uri.getPath())); } - return new HDFSLocation(this, new Path(fileSystem.getUri() + "/" + pathBase + "/" + uri.getPath())); + + return create(uri.getPath()); } @Override http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/test/java/org/apache/twill/filesystem/FileContextLocationTest.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/test/java/org/apache/twill/filesystem/FileContextLocationTest.java b/twill-yarn/src/test/java/org/apache/twill/filesystem/FileContextLocationTest.java new file mode 100644 index 0000000..e4c3774 --- /dev/null +++ b/twill-yarn/src/test/java/org/apache/twill/filesystem/FileContextLocationTest.java @@ -0,0 +1,50 @@ +/* + * 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.twill.filesystem; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.hdfs.MiniDFSCluster; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import java.io.IOException; + +/** + * + */ +public class FileContextLocationTest extends LocationTestBase { + + private static MiniDFSCluster dfsCluster; + + @BeforeClass + public static void init() throws IOException { + Configuration conf = new Configuration(); + conf.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, tmpFolder.newFolder().getAbsolutePath()); + dfsCluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build(); + } + + @AfterClass + public static void finish() { + dfsCluster.shutdown(); + } + + @Override + protected LocationFactory createLocationFactory(String pathBase) throws Exception { + return new FileContextLocationFactory(dfsCluster.getFileSystem().getConf(), pathBase); + } +} http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/test/java/org/apache/twill/filesystem/HDFSLocationTest.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/test/java/org/apache/twill/filesystem/HDFSLocationTest.java b/twill-yarn/src/test/java/org/apache/twill/filesystem/HDFSLocationTest.java index 20f7403..d57d49f 100644 --- a/twill-yarn/src/test/java/org/apache/twill/filesystem/HDFSLocationTest.java +++ b/twill-yarn/src/test/java/org/apache/twill/filesystem/HDFSLocationTest.java @@ -30,14 +30,12 @@ import java.io.IOException; public class HDFSLocationTest extends LocationTestBase { private static MiniDFSCluster dfsCluster; - private static LocationFactory locationFactory; @BeforeClass public static void init() throws IOException { Configuration conf = new Configuration(); conf.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, tmpFolder.newFolder().getAbsolutePath()); dfsCluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build(); - locationFactory = new HDFSLocationFactory(dfsCluster.getFileSystem()); } @AfterClass @@ -46,7 +44,7 @@ public class HDFSLocationTest extends LocationTestBase { } @Override - protected LocationFactory getLocationFactory() { - return locationFactory; + protected LocationFactory createLocationFactory(String pathBase) throws Exception { + return new HDFSLocationFactory(dfsCluster.getFileSystem(), pathBase); } } http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java b/twill-yarn/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java index 3f6d931..ba21beb 100644 --- a/twill-yarn/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java +++ b/twill-yarn/src/test/java/org/apache/twill/filesystem/LocalLocationTest.java @@ -17,24 +17,17 @@ */ package org.apache.twill.filesystem; -import org.junit.BeforeClass; - -import java.io.IOException; +import java.io.File; /** * */ public class LocalLocationTest extends LocationTestBase { - private static LocationFactory locationFactory; - - @BeforeClass - public static void init() throws IOException { - locationFactory = new LocalLocationFactory(tmpFolder.newFolder()); - } - @Override - protected LocationFactory getLocationFactory() { - return locationFactory; + protected LocationFactory createLocationFactory(String pathBase) throws Exception { + File basePath = new File(tmpFolder.newFolder(), pathBase); + basePath.mkdirs(); + return new LocalLocationFactory(basePath); } } http://git-wip-us.apache.org/repos/asf/incubator-twill/blob/388a6d92/twill-yarn/src/test/java/org/apache/twill/filesystem/LocationTestBase.java ---------------------------------------------------------------------- diff --git a/twill-yarn/src/test/java/org/apache/twill/filesystem/LocationTestBase.java b/twill-yarn/src/test/java/org/apache/twill/filesystem/LocationTestBase.java index ee591e7..e01115b 100644 --- a/twill-yarn/src/test/java/org/apache/twill/filesystem/LocationTestBase.java +++ b/twill-yarn/src/test/java/org/apache/twill/filesystem/LocationTestBase.java @@ -17,13 +17,23 @@ */ package org.apache.twill.filesystem; +import com.google.common.base.Charsets; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.io.CharStreams; import org.junit.Assert; import org.junit.ClassRule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; import java.net.URI; +import java.net.URISyntaxException; import java.util.List; /** @@ -34,10 +44,60 @@ public abstract class LocationTestBase { @ClassRule public static TemporaryFolder tmpFolder = new TemporaryFolder(); + private final LoadingCache<String, LocationFactory> locationFactoryCache = CacheBuilder.newBuilder() + .build(new CacheLoader<String, LocationFactory>() { + @Override + public LocationFactory load(String key) throws Exception { + return createLocationFactory(key); + } + }); + + @Test + public void testBasic() throws Exception { + LocationFactory factory = locationFactoryCache.getUnchecked("basic"); + URI baseURI = factory.create("/").toURI(); + + // Test basic location construction + Assert.assertEquals(factory.create("/file"), factory.create("/file")); + Assert.assertEquals(factory.create("/file2"), + factory.create(URI.create(baseURI.getScheme() + ":" + baseURI.getPath() + "/file2"))); + Assert.assertEquals(factory.create("/file3"), + factory.create( + new URI(baseURI.getScheme(), baseURI.getAuthority(), + baseURI.getPath() + "/file3", null, null))); + Assert.assertEquals(factory.create("/"), factory.create("/")); + Assert.assertEquals(factory.create("/"), factory.create(URI.create(baseURI.getScheme() + ":" + baseURI.getPath()))); + + Assert.assertEquals(factory.create("/"), + factory.create(new URI(baseURI.getScheme(), baseURI.getAuthority(), + baseURI.getPath(), null, null))); + + // Test file creation and rename + Location location = factory.create("/file"); + Assert.assertTrue(location.createNew()); + Assert.assertTrue(location.exists()); + + Location location2 = factory.create("/file2"); + String message = "Testing Message"; + try (Writer writer = new OutputStreamWriter(location2.getOutputStream(), Charsets.UTF_8)) { + writer.write(message); + } + long length = location2.length(); + long lastModified = location2.lastModified(); + + location2.renameTo(location); + + Assert.assertFalse(location2.exists()); + try (Reader reader = new InputStreamReader(location.getInputStream(), Charsets.UTF_8)) { + Assert.assertEquals(message, CharStreams.toString(reader)); + } + Assert.assertEquals(length, location.length()); + Assert.assertEquals(lastModified, location.lastModified()); + } @Test public void testDelete() throws IOException { - LocationFactory factory = getLocationFactory(); + LocationFactory factory = locationFactoryCache.getUnchecked("delete"); Location base = factory.create("test").getTempFile(".tmp"); Assert.assertTrue(base.mkdirs()); @@ -57,7 +117,7 @@ public abstract class LocationTestBase { @Test public void testHelper() { - LocationFactory factory = LocationFactories.namespace(getLocationFactory(), "testhelper"); + LocationFactory factory = LocationFactories.namespace(locationFactoryCache.getUnchecked("helper"), "testhelper"); Location location = factory.create("test"); Assert.assertTrue(location.toURI().getPath().endsWith("testhelper/test")); @@ -68,7 +128,7 @@ public abstract class LocationTestBase { @Test public void testList() throws IOException { - LocationFactory factory = getLocationFactory(); + LocationFactory factory = locationFactoryCache.getUnchecked("list"); Location dir = factory.create("dir"); @@ -107,5 +167,5 @@ public abstract class LocationTestBase { } } - protected abstract LocationFactory getLocationFactory(); + protected abstract LocationFactory createLocationFactory(String pathBase) throws Exception; }
